31

1つのクエリで3つのテーブルにデータを挿入したい。
私のテーブル以下のようになります。Postgresを使用して一度に3つのテーブルにデータを挿入する

CREATE TABLE sample (
    id  bigserial PRIMARY KEY, 
    lastname varchar(20), 
    firstname varchar(20) 
); 

CREATE TABLE sample1(
    user_id bigserial PRIMARY KEY, 
    sample_id bigint REFERENCES sample, 
    adddetails varchar(20) 
); 

CREATE TABLE sample2(
    id  bigserial PRIMARY KEY, 
    user_id bigint REFERENCES sample1, 
    value varchar(10) 
); 

私はすべての挿入と引き換えに鍵を取得し、私は次の表に、そのキーを挿入する必要があります。

insert into sample(firstname,lastname) values('fai55','shaggk') RETURNING id; 
insert into sample1(sample_id, adddetails) values($id,'ss') RETURNING user_id; 
insert into sample2(user_id, value) values($id,'ss') RETURNING id; 

しかし、私は、単一のクエリを実行する場合、彼らは私に値を戻し、私はすぐに次のクエリでそれらを再利用することはできません。
私のクエリがあります。

これを行うには?

答えて

1

サンプルテーブルに挿入後トリガーを作成して、他の2つのテーブルに挿入することができます。

これを行う際に見る唯一の問題は、adddetailsを挿入する方法がないことです。これは、常に空であるか、この場合はssです。実際にサンプルテーブルにないサンプルにカラムを挿入する方法はありませんので、インティアル挿入物と一緒に送ることはできません。

また、挿入を実行するストアドプロシージャを作成することもできます。

あなたはここでどのデータベースについて話しているのですか?

8

この

with first_insert as (
    insert into sample(firstname,lastname) 
    values('fai55','shaggk') 
    RETURNING id 
), 
second_insert as (
    insert into sample1(id ,adddetails) 
    values 
    ((select id from first_insert), 'ss') 
    RETURNING user_id 
) 
insert into sample2 (id ,adddetails) 
values 
((select user_id from first_insert), 'ss'); 

ような何かsample2への挿入から生成されたIDが必要とされないように、私は最後の挿入からreturning句を削除しました。

60

使用data-modifying CTEs

WITH ins1 AS (
    INSERT INTO sample(firstname, lastname) 
    VALUES ('fai55', 'shaggk') 
-- ON  CONFLICT DO NOTHING    -- optional addition in Postgres 9.5+ 
    RETURNING id AS user_id 
    ) 
, ins2 AS (
    INSERT INTO sample1 (user_id, adddetails) 
    SELECT user_id, 'ss' FROM ins1 
    -- RETURNING user_id      -- only if used in turn 
    ) 
INSERT INTO sample2 (user_id, value)   -- same here 
SELECT user_id, 'ss' FROM ins1; 

各インサートは、前のものに依存します。 VALUESの代わりにSELECTを使用すると、前の挿入から行が戻されない場合は、補助表に何も挿入されません。 (Related:Postgres 9.5以降のON CONFLICT句)
これはちょっと短くて速いです。 VALUES表現とは対照的に、あなたは(別のVALUES式の中で明示的な型キャストが必要な場合があります

WITH data(firstname, lastname, adddetails, value) AS (
    VALUES         -- provide data here 
     (text 'fai55', text 'shaggk', text 'ss', text 'ss2') -- see below 
     -- more?       -- works for multiple input rows 
    ) 
, ins1 AS (
    INSERT INTO sample (firstname, lastname) 
    SELECT firstname, lastname FROM data -- DISTINCT? see below 
    ON  CONFLICT DO NOTHING    -- required UNIQUE constraint 
    RETURNING firstname, lastname, id AS sample_id 
    ) 
, ins2 AS (
    INSERT INTO sample1 (sample_id, adddetails) 
    SELECT sample_id, adddetails 
    FROM data 
    JOIN ins1 USING (firstname, lastname) 
    RETURNING sample_id, user_id 
    ) 
INSERT INTO sample2 (user_id, value) 
SELECT user_id, value 
FROM data 
JOIN ins1 USING (firstname, lastname) 
JOIN ins2 USING (sample_id); 

が一箇所に完全なデータ行を提供するために、


一般的に、それはより便利ですINSERTにアタッチされ、データ型はターゲット表から派生します。

複数の行にはidenti CAL (firstname, lastname)、あなたは最初の挿入のための重複を折るする必要があります。

... 
INSERT INTO sample (firstname, lastname) 
SELECT DISTINCT firstname, lastname FROM data 
... 

あなたは、データ・ソースの代わりに、CTE dataとして(一時的な)テーブルを使用することができます。

関連は、より多くの詳細を:通常

+0

ありがとう私は、任意の挿入が.yesを発生しなかった場合アウトトランザクションのロールを追加どのように私 – Faisal

+1

これは、単一のSQL文であることができます。複数の文を1つのトランザクションに束ねることはできますが、1つのトランザクションを分割することはできません。また、彼のコメントでデニスが言うこと。私は私の答えにいくつかのリンクを付け加えました。 –

+0

しかし、あなたはCTEの中にSELECTを持つことができますし、すぐにそれをINSERTと一緒に使用した後にできますか? – mmcrae

4

、あなたは複雑なクエリを記述避けるためにトランザクションを使用すると思います。また、あなたのPostgresのタグが正しいと仮定すると、CTEを使用することができ

http://www.postgresql.org/docs/current/static/sql-begin.html

http://dev.mysql.com/doc/refman/5.7/en/commit.html

。例えば:再生のため

with sample_ids as (
    insert into sample(firstname, lastname) 
    values('fai55','shaggk') 
    RETURNING id 
), sample1_ids as (
    insert into sample1(id, adddetails) 
    select id,'ss' 
    from sample_ids 
    RETURNING id, user_id 
) 
insert into sample2(id, user_id, value) 
select id, user_id, 'val' 
from sample1_ids 
RETURNING id, user_id; 
+0

thanxどうすればいいですか?挿入が失敗した場合はこのクエリでトランザクションを達成するロールバックを行うことができる – Faisal

+0

その後、トランザクション全体(またはcte)がロールバックされるため、クエリを修正した後で、すべてをやり直します。 Btw、あなたのインサートが時々失敗するならば、おそらく何か間違っているでしょう。挿入が失敗する唯一のケースは、同時トランザクション中に重複したユニークキーに実行されるアップサンプリングのシナリオであり、さらには、あなたが弾丸を作成する必要がある場合には、アドバイザリロックまたはテーブルロックを取得できます。 –

関連する問題