Postgres 9.2 PL/pgSQL 循环简单更新

Posted

技术标签:

【中文标题】Postgres 9.2 PL/pgSQL 循环简单更新【英文标题】:Postgres 9.2 PL/pgSQL simple update in loop 【发布时间】:2012-12-10 15:16:31 【问题描述】:

我有一张下表:

+----+----------+----------+
| id | trail_id | position |
+----+----------+----------+
| 11 | 16       | NULL     |
| 12 | 121      | NULL     |
| 15 | 121      | NULL     |
| 19 | 42       | NULL     |
| 20 | 42       | NULL     |
| 21 | 42       | NULL     |
+----+----------+----------+

我正在寻找一种简单的方法来更新 position 递增整数( per parent )。所以完成后,表格应该是这样的:

+----+-----------+----------+
| id | trail_id  | position |
+----+-----------+----------+
| 11 | 16        | 1        |
| 12 | 121       | 1        |
| 15 | 121       | 2        |
| 19 | 42        | 1        |
| 20 | 42        | 2        |
| 21 | 42        | 3        |
+----+-----------+----------+

我认为我需要的是一个函数,它循环遍历给定trail 的所有行,具有简单的递增索引并更新position 列。但是,我是 pgSQL 新手,所以我很高兴听到有更简单的方法可以做到这一点。

我现在尝试的解决方案是这样的

CREATE FUNCTION fill_positions(tid integer) RETURNS integer AS $$
DECLARE
    pht RECORD;
    i INTEGER := 0;
BEGIN
    FOR pht IN SELECT * FROM photos WHERE photos.trail_id = tid LOOP
        i := i + 1;
        UPDATE photos SET position = i WHERE id = pht.id;
    END LOOP;
    RETURN i;
END;
$$ LANGUAGE plpgsql;

我很确定它可以更干净,并且不必使用函数。

【问题讨论】:

我稍微改变了我原来的问题。最初我认为执行由于某些错误而冻结,但事实并非如此。我正在使用一个 GUI 客户端,它的一个进程在尝试修改 photos 表时冻结,这当然会为任何其他尝试更新它的进程锁定表。现在一切都很好,我发布的解决方案有效,我正在寻找更好的解决方案' 【参考方案1】:

您不需要为此存储函数。你可以用一条语句来做到这一点。

with new_numbers as (
   select id,  
          trail_id,
          row_number() over (partition by trail_id order by id) as position
   from photos
)
update photos
  set position = nn.position
from new_numbers nn
where nn.id = photos.id;

【讨论】:

天哪,我正在尝试编辑我的初始帖子,以便您的答案适合(那是我的错误,我在问题中使用了不同的名称),但我认为你也在改变你的答案:) row_number() 方法也让我大吃一惊。这是完美的。

以上是关于Postgres 9.2 PL/pgSQL 循环简单更新的主要内容,如果未能解决你的问题,请参考以下文章

PL/pgSQL“for循环”+选择基本示例(“hello world”)

循环通过 PL/PGSQL 中的 CURSOR 而不锁定表

PL/pgSQL 代码的问题

Postgres PL/pgSQL,可以声明匿名自定义类型吗?

使用 PostgreSQL PL/pgSQL 在 For 循环中添加月份

PL/pgSQL 循环遍历多个模式、表和行