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
を含む別の行がすでに存在するというエラーが表示されます。
UPDATE
with _ORDER BY
_タイトルで出された質問に関して:SQL UPDATE
コマンドには_ORDER BY
_がありません。 Postgresは任意の順序で行を更新します。ただし、制約を各行の後、各ステートメントの後、またはトランザクションの最後にチェックするかどうかを決定する(制限された)オプションがあります。 DEFERRABLE
制約を使用すると、intermediate状態の重複キー違反を回避できます。
私はこの質問の下で私たちが解決したことを引用しています:
_NOT DEFERRED
_制約は、各行の後にチェックされます。
DEFERRABLE
制約がIMMEDIATE
に設定されている(_INITIALLY IMMEDIATE
_または_SET CONSTRAINTS
_を介して)は、各ステートメントの後にチェックされます。
ただし、制限があります。外部キー制約では、ターゲット列にnon-deferrable制約が必要です。
参照される列は、参照されるテーブルの遅延できない一意キーまたは主キー制約の列である必要があります。
質問の更新後に更新されました。
通常の操作で_"sequence"
_が負になることはないと仮定すると、次のような固有のエラーを回避できます。
_UPDATE tbl SET "sequence" = ("sequence" + 1) * -1
WHERE "CableLine" = 2;
UPDATE tbl SET "sequence" = "sequence" * -1
WHERE "CableLine" = 2
AND "sequence" < 0;
_
遅延できない制約(デフォルト)では、これを機能させるために2つの個別のコマンドを実行する必要があります。同時実行の問題を回避するために、コマンドをすばやく連続して実行します。このソリューションは明らかに重い同時負荷には適していません。
余談:
テーブルエイリアスの場合、ワードAS
をスキップしても問題ありませんが、列エイリアスの場合は同じようにしないことをお勧めします。
許可されていても、SQLキーワードを識別子として使用しないことをお勧めします。
大規模な場合、または同時負荷の高いデータベースの場合、行の相対的な順序付けに serial
列を使用する方が賢明です。ビューまたはクエリでウィンドウ関数row_number()
を使用すると、1から始まり、ギャップのない数値を生成できます。この関連する回答を検討してください:
UPDATE
with 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
については、誰にとっても有用であるとは思えません。
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;
これは私のために働きました:
[ここでステートメントを更新] OPTION(MAXDOP 1)-レコードが更新される順序を利用する熱心なスプールの使用を行サイズが引き起こすのを防ぎます。
私はクラスター化されたintインデックスを順次(必要に応じて生成)で使用し、最近まで問題がありませんでした。それでも、クエリプランオプティマイザーが(逆に)遅延スプールを使用することを決定した小さな行セットでのみ問題がありました。
理論的には、新しいオプションを使用してスプールの使用を禁止することもできますが、maxdopの方が簡単です。
計算が分離されているため(シングルユーザー)、私は独特の状況にあります。別の状況では、競合を回避するためにmaxdop制限を使用する代わりの方法が必要になる場合があります。
Postgresqlのtable_id_seqを1から並べ替えて、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();
レイジーウェイ、(別名最速または最良の方法ではありません)
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)