sql >> データベース >  >> RDS >> PostgreSQL

関連するテーブルから選択して、1つのクエリで複数のテーブルに行を挿入します

    最終バージョン

    ...OPからのいくつかの詳細情報の後。このデモを検討してください:

    -- DROP TABLE foo; DROP TABLE bar;
    
    CREATE TEMP TABLE bar (
     id serial PRIMARY KEY  -- using a serial column!
    ,z  integer NOT NULL
    );
    
    CREATE TEMP TABLE foo (
     id     serial PRIMARY KEY  -- using a serial column!
    ,x      integer NOT NULL
    ,y      integer NOT NULL
    ,bar_id integer UNIQUE NOT NULL REFERENCES bar(id)
    );
    

    値を挿入-bar 最初に。
    それは非常に役に立ちます このような質問でテストデータを提供した場合!

    INSERT INTO bar (id,z) VALUES
     (100, 7)
    ,(101,16)
    ,(102,21);
    
    INSERT INTO foo (id, x, y, bar_id) VALUES
     (1, 3,4,100)
    ,(2, 9,6,101)
    ,(3,18,0,102);
    

    シーケンスを現在の値に設定しないと、重複するキー違反が発生します:

    SELECT setval('foo_id_seq', 3);
    SELECT setval('bar_id_seq', 102);
    

    チェック:

    -- SELECT nextval('foo_id_seq')
    -- SELECT nextval('bar_id_seq')
    -- SELECT * from bar;
    -- SELECT * from foo;
    

    クエリ:

    WITH a AS (
        SELECT f.x, f.y, bar_id, b.z
        FROM   foo f
        JOIN   bar b ON b.id = f.bar_id
        WHERE  x > 3
        ),b AS (
        INSERT INTO bar (z)
        SELECT z
        FROM   a
        RETURNING z, id AS bar_id
        )
    INSERT INTO foo (x, y, bar_id)
    SELECT a.x, a.y, b.bar_id
    FROM   a
    JOIN   b USING (z);
    

    これにより、前回の更新で説明されていることが実行されます。

    クエリはzを想定しています はUNIQUE zの場合 ユニークではなく、より複雑になります。ウィンドウ関数row_number()を使用したすぐに解決できるソリューションについては、この関連する回答のクエリ2を参照してください。 この場合。

    また、 1:1の関係を置き換えることを検討してください fooの間 およびbar 単一の統合されたテーブルで。

    データ変更CTE

    詳細情報の後の2番目の回答。

    fooに行を追加する場合 および バー PostgreSQL 9.1 以降、1つのクエリでデータ変更CTEを使用できます :

    WITH x AS (
        INSERT INTO bar (col1, col2)
        SELECT f.col1, f.col2
        FROM   foo f
        WHERE  f.id BETWEEN 12 AND 23 -- some filter
        RETURNING col1, col2, bar_id  -- assuming bar_id is a serial column
        )
    INSERT INTO foo (col1, col2, bar_id)
    SELECT col1, col2, bar_id
    FROM   x;
    

    fooから値を描画します 、 barに挿入します 、自動生成された bar_idと一緒に返送してもらいます それを挿入します fooに 。他のデータも使用できます。

    これがsqlfiddleで遊ぶための実用的なデモです。

    基本

    説明の前に基本的な情報を含む元の回答。
    基本的な形式は次のとおりです。

    INSERT INTO foo (...)
    SELECT ... FROM foo WHERE ...
    

    括弧は必要ありません。どのテーブルでも同じことができます

    INSERT INTO foo (...)
    SELECT ... FROM bar WHERE ...
    

    そして、SELECTで挿入したテーブルに参加できます:

    INSERT INTO foo (...)
    SELECT f.col1, f.col2, .. , b.bar_id
    FROM   foo f
    JOIN   bar b USING (foo_id);  -- present in foo and bar
    

    これは、他のSELECTと同じように、挿入先のテーブルを含めることができる単なるSELECTです。行は最初に読み取られ、次に挿入されます。



    1. 統計の自動更新がクエリのパフォーマンスにどのように影響するか

    2. MySQLでNOTNULL制約を追加する方法

    3. LinuxからのSQLServerBULK INSERT

    4. PL / SQLでループを使用せずに1から10を印刷するにはどうすればよいですか?