12

自動インクリメント整数を主キーとして使用する PostgreSQL 9 データベースがあります。1 つまたは 2 つの値を変更しながら、(いくつかのフィルター条件に基づいて) テーブル内のいくつかの行を複製したい、つまり、ID (自動生成されたもの) と場合によっては別の列を除いて、すべての列の値をコピーしたい。

ただし、古い ID から新しい ID へのマッピングも取得したいと考えています。最初にコピーする行を照会してから、一度に 1 つずつ新しい行を挿入するより良い方法はありますか?

本質的に私はこのようなことをしたい:

INSERT INTO my_table (col1, col2, col3)
SELECT col1, 'new col2 value', col3
FROM my_table old
WHERE old.some_criteria = 'something'
RETURNING old.id, id;

ただし、これは失敗しERROR: missing FROM-clause entry for table "old"、理由がわかります。Postgres は最初に SELECT を実行してから挿入する必要があり、RETURNING句は新しく挿入された行にのみアクセスできます。

4

5 に答える 5

10

RETURNING は、挿入された最後の行の列のみを参照できます。「OLD」ID と新しい ID の両方を保持する列がテーブルにない限り、この方法で「OLD」ID を参照することはできません。

これを実行してみてください。動作するはずであり、RETURNING 経由で取得できるすべての可能な値が表示されます。

INSERT INTO my_table (col1, col2, col3)
    SELECT col1, 'new col2 value', col3
    FROM my_table AS old
    WHERE old.some_criteria = 'something'
RETURNING *;

希望する動作は得られませんが、RETURNING がどのように機能するように設計されているかをよりよく説明する必要があります。

于 2011-08-21T00:09:55.130 に答える
4

これは、データ変更 CTE (Postgres 9.1+ )の助けを借りて行うことができます。

WITH sel AS (
   SELECT id, col1, col3
        , row_number() OVER (ORDER BY id) AS rn  -- order any way you like
   FROM   my_table
   WHERE  some_criteria = 'something'
   ORDER  BY id  -- match order or row_number()
   )
,    ins AS (
   INSERT INTO my_table (col1, col2, col3)
   SELECT col1, 'new col2 value', col3
   FROM   sel
   ORDER  BY id  -- redundant to be sure
   RETURNING id
 )
SELECT s.id AS old_id, i.id AS new_id
FROM  (SELECT id, row_number() OVER (ORDER BY id) AS rn FROM ins) i
JOIN   sel s USING (rn);

SQL フィドルのデモ。

SELECTこれは、 a からの行が提供された順序で挿入される (および提供された順序で返される)という文書化されていない実装の詳細に依存しています。Postgres の現在のすべてのバージョンで動作し、壊れることはありません。関連している:

RETURNINGウィンドウ関数は句では許可されていないためrow_number()、別のサブクエリで適用します。

この関連する後の回答での詳細な説明:

于 2015-03-25T18:51:47.243 に答える
2

良い!このコードをテストしますが、( FROM my_table AS old) 内の ( FROM my_table) と( WHERE old.some_criteria = 'something')内の ( WHERE some_criteria = 'something')を変更します。

これは私が使用する最終的なコードです

INSERT INTO my_table (col1, col2, col3)
    SELECT col1, 'new col2 value', col3
    FROM my_table AS old
    WHERE some_criteria = 'something'
RETURNING *;

ありがとう!

于 2013-04-17T14:47:21.597 に答える
0

「old」は予約語で、ルール書き換えシステムで使用されます。[このクエリ フラグメントはルールの一部ではないと思います。その場合、あなたは質問を別の言い方で表現したでしょう]

于 2011-08-22T13:03:32.337 に答える