需要与UPDATE
“绑定”ORDER 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;
如何正确地做到这一点?
没有光标,当我这样做时:
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"
我得到了唯一的错误。因此,需要从最终而不是从头开始更新。
表:
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
的另一行。
答案 0 :(得分:12)
UPDATE
与ORDER BY
:
UPDATE thetable
SET columntoupdate=yourvalue
FROM (SELECT rowid, 'thevalue' AS yourvalue
FROM thetable
ORDER BY rowid
) AS t1
WHERE thetable.rowid=t1.rowid;
UPDATE
顺序仍然是随机的(我猜),但提供给UPDATE
命令的值与thetable.rowid=t1.rowid
条件匹配。所以我要做的是,首先选择内存中的“更新”表,在上面的代码中将其命名为t1
,然后使我的物理表看起来与t1
相同。更新顺序不再重要。
对于真正有序的UPDATE
,我认为它对任何人都没有用。
答案 1 :(得分:10)
UPDATE
的ORDER BY
关于提出的问题标题:SQL ORDER BY
命令中没有UPDATE
。 Postgres以任意顺序更新行。但是您有(有限的)选项来决定是在每行之后,每个语句之后还是在事务结束时检查约束。您可以避免对具有DEFERRABLE
约束的中间状态的重复键冲突。
我引用了我们在这个问题下制定的内容:
Constraint defined DEFERRABLE INITIALLY IMMEDIATE is still DEFERRED?
NOT DEFERRED
约束在每行后检查。
DEFERRABLE
(IMMEDIATE
或通过INITIALLY IMMEDIATE
)的 SET CONSTRAINTS
约束在每个声明后检查。
但是有一些限制。外键约束要求目标列上的不可延迟的约束。
引用的列必须是不可延迟的唯一列 或引用表中的主键约束。
更新问题后更新。
假设"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
列进行行的相对排序更明智。您可以在视图或查询中生成以1开头且没有窗口函数row_number()
的间隙的数字。考虑这个相关的答案:
Is it possible to use a PG sequence on a per record label?
答案 2 :(得分: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;
答案 3 :(得分: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)
答案 4 :(得分:0)
这对我有用:
[此处更新声明] 选项(MAXDOP 1) - 防止行大小导致使用急切线轴,这会破坏记录更新的顺序。
我按顺序使用聚簇int索引(如果需要,生成一个)并且直到最近才出现问题,即使这样,只有在小行集上(反直觉地)查询计划优化器决定使用惰性假脱机
理论上我可以使用新选项来禁止使用假脱机,但我发现maxdop更简单。
我处于一种独特的情况,因为计算是孤立的(单个用户)。不同的情况可能需要使用maxdop限制来替代争用。
答案 5 :(得分:0)
如果有人来这里,就像我来解决从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();