16

需要UPDATEORDER BY. 我正在尝试使用游标,但出现错误:

cursor "cursupd" doesn't specify a line,
SQL state: 24000

代码:

BEGIN;
    DECLARE cursUpd CURSOR FOR SELECT * FROM "table" WHERE "field" = 5760 AND "sequence" >= 0 AND "sequence" < 9 ORDER BY "sequence" DESC;
    UPDATE "table" SET "sequence" = "sequence" + 2 WHERE CURRENT OF cursUpd;
    CLOSE cursUpd;
COMMIT;

如何正确执行?

更新 1

没有光标,当我这样做时:

UPDATE "CableLinePoint" AS "t"
SET "sequence" = t."sequence" + 2
from (
    select max("sequence") "sequence", "id"
    from "CableLinePoint"
    where
        "CableLine" = 5760
    group by "id"
    ORDER BY "sequence" DESC
) "s"
where "t"."id" = "s"."id" and "t"."sequence" = "s"."sequence"

我得到了独特的错误。所以,需要从头更新,而不是从头更新。

更新 2

桌子:

id|CableLine|sequence
10|    2    |    1
11|    2    |    2
12|    2    |    3
13|    2    |    4
14|    2    |    5

需要更新(增加)字段“序列”。“序列”有“索引”类型,所以不能这样做:

UPDATE "table" SET "sequence" = "sequence" + 1 WHERE "CableLine" = 2

当行中的“序列”id = 10增加时,1我收到另一行"sequence" = 2已经存在的错误。

4

6 回答 6

17

UPDATEORDER BY

UPDATE thetable 
  SET columntoupdate=yourvalue 
 FROM (SELECT rowid, 'thevalue' AS yourvalue 
         FROM thetable 
        ORDER BY rowid
      ) AS t1 
WHERE thetable.rowid=t1.rowid;

UPDATEorder 仍然是随机的(我猜),但提供给UPDATEcommand 的值由thetable.rowid=t1.rowid条件匹配。所以我要做的是,首先选择内存中的“更新”表,它t1在上面的代码中命名,然后让我的物理表看起来与t1. 并且更新顺序不再重要。

至于真正的有序UPDATE,我认为它对任何人都没有用。

于 2015-04-20T12:22:42.233 回答
14

UPDATEORDER BY

至于标题提出的问题:ORDER BYSQLUPDATE命令中没有。Postgres 以任意顺序更新行。但是您有(有限的)选项来决定是在每行之后、每条语句之后还是在事务结束时检查约束。您可以避免具有约束的中间状态的重复键违规。DEFERRABLE

我引用了我们在这个问题下得出的结论:

不过也有限制。外键约束需要对目标列进行不可延迟的约束。

被引用的列必须是被引用表中不可延迟的唯一或主键约束的列。

解决方法

问题更新后更新。
假设"sequence"在正常操作中永远不会出现负数,您可以避免这样的独特错误:

UPDATE tbl SET "sequence" = ("sequence" + 1) * -1
WHERE  "CableLine" = 2;

UPDATE tbl SET "sequence" = "sequence" * -1
WHERE  "CableLine" = 2
AND    "sequence" < 0;

使用不可延迟约束(默认),您必须运行两个单独的命令才能使其工作。快速连续运行命令以避免并发问题。该解决方案显然不适合繁重的并发负载。

另外:
跳过表别名的关键字AS是可以的,但不鼓励对列别名做同样的事情。

我建议不要使用 SQL 关键字作为标识符,即使这是允许的。

避免问题

在更大的规模或并发负载较重的数据库中,使用serial列来进行行的相对排序更为明智。row_number()您可以在视图或查询中使用窗口函数生成以 1 开头且没有间隙的数字。考虑这个相关的答案:

于 2013-05-24T14:34:46.110 回答
1

如果有人像我一样来这里是为了解决从 1 重新排列 postgresql table_id_seq 并按 id 排序的问题。我尝试的解决方案部分取自@Syd Nazam Ul Hasan(上图)和https://gist.github.com/JoshCheek/e19f83f271dc16d7825e2e4079538ba8

CREATE OR REPLACE FUNCTION update_sequence()
RETURNS SETOF varchar AS $$
DECLARE
  curs CURSOR FOR SELECT * FROM table ORDER BY id ASC;
  row  RECORD;
  v INTEGER := 0;
BEGIN
  open curs;
  LOOP
    FETCH FROM curs INTO row;
    update table 
    set id = v+1
    where id = row.id;
    v = v+1;
    EXIT WHEN NOT FOUND;
    return next row.id;
  END LOOP;
END; $$ LANGUAGE plpgsql;

SELECT update_sequence();
于 2019-11-17T19:13:20.340 回答
1
Update with Order By
Declare 
v number;
cursor c1 is 
    Select col2 from table1 order by col2;
    begin
    v:=0;
     for c in c1
     loop
    update table1 
    set col1 =v+1
    where col2 = c.col2;
    end loop;
    commit;
    END;
于 2019-05-10T06:43:54.890 回答
0

懒惰的方式,(也不是最快或最好的方式)

CREATE OR REPLACE FUNCTION row_number(table_name text, update_column text, start_value integer, offset_value integer, order_by_column text, order_by_descending boolean)
  RETURNS void AS
$BODY$
DECLARE
    total_value integer;
    my_id text;
    command text;
BEGIN
total_value = start_value;
    command = 'SELECT ' || order_by_column || ' FROM ' || table_name || ' ORDER BY '  || order_by_column;

    if (order_by_descending) THEN
        command = command || ' desc';
    END IF;

    FOR  my_id in  EXECUTE command LOOP
        command = 'UPDATE ' || table_name || ' SET  ' || update_column || ' = ' || total_value || ' WHERE ' || order_by_column || ' = ' ||  my_id|| ';';

        EXECUTE command;
        total_value = total_value + offset_value;
    END LOOP;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;

例子

SELECT row_number('regispro_spatial_2010.ags_states_spatial', 'order_id', 10,1, 'ogc_fid', true)

于 2014-05-05T19:27:51.253 回答
0

这对我有用:

[此处更新语句] OPTION (MAXDOP 1) -- 防止行大小导致使用急切假脱机,这会破坏记录更新的顺序。

我按顺序使用聚集的 int 索引(如果需要,生成一个),直到最近才出现问题,即使那时也只在查询计划优化器决定使用惰性假脱机的小行集上(违反直觉)。

从理论上讲,我可以使用新选项来禁止使用 spool,但我发现 maxdop 更简单。

我处于一个独特的情况,因为计算是孤立的(单个用户)。不同的情况可能需要使用 maxdop 限制的替代方法来避免争用。

于 2016-03-04T20:45:15.413 回答