0

postgresには、次のような2つのテーブルがあります

CREATE TABLE foo ( 
    pkey   SERIAL PRIMARY KEY,
    name   TEXT
);

CREATE TABLE bar (
   pkey SERIAL PRIMARY KEY,
   foo_fk INTEGER REFERENCES foo(pkey) NOT NULL,
   other  TEXT
 ); 

私がやりたいことは、次のことを行う .sql スクリプト ファイルを作成することです。

INSERT INTO foo(name) VALUES ('A') RETURNING pkey AS abc; 
INSERT INTO bar(foo_fk,other) VALUES 
               (abc, 'other1'),
               (abc, 'other2'),
               (abc, 'other3');

pgAdminで以下のエラーが発生します

Query result with 1 row discarded.
ERROR:  column "abc" does not exist
LINE 3:                    (abc, 'other1'),

********** Error **********

ERROR: column "abc" does not exist
SQL state: 42703
Character: 122

ストアド プロシージャの外では、ステートメント間で使用できる変数をどのように定義しますか? 挿入から foo に返された pkey を使用してバーに挿入できるようにするための他の構文はありますか。

4

3 に答える 3

5

クエリを 1 つに結合できます。何かのようなもの:

with foo_ins as (INSERT INTO foo(name) 
                 VALUES ('A') 
                 RETURNING pkey AS foo_id)
INSERT INTO bar(foo_fk,other)
SELECT foo_id, 'other1' FROM foo_ins
UNION ALL
SELECT foo_id, 'other2' FROM foo_ins
UNION ALL
SELECT foo_id, 'other3' FROM foo_ins;

その他のオプション - 次のような匿名の PL/pgSQL ブロックを使用します。

DO $$
DECLARE foo_id INTEGER;
BEGIN
    INSERT INTO foo(name) 
    VALUES ('A') 
    RETURNING pkey INTO foo_id;

    INSERT INTO bar(foo_fk,other) 
    VALUES         (foo_id, 'other1'),
                   (foo_id, 'other2'),
                   (foo_id, 'other3');
END$$;
于 2013-10-12T18:30:24.013 に答える
3

あなたはに使用lastval()することができます...

nextval現在のセッションでによって最後に返された値を返します。

この方法では、使用されるシーケンスの名前を知る必要はありません。

INSERT INTO foo(name) VALUES ('A');
INSERT INTO bar(foo_fk,other) VALUES 
   (lastval(), 'other1')
  ,(lastval(), 'other2')
  ,(lastval(), 'other3');

これは、自分のセッションで最後に呼び出したものを制御できるため安全です。


@Igor によって提案された書き込み可能な CTEを使用する場合。2 番目の INSERT ステートメントで短い式を引き続き使用できます。それを a と組み合わせます (または、単にコンマの後に CTE テーブルを追加します。同じことです):VALUESCROSS JOIN

WITH ins AS (
   INSERT INTO foo(name) 
   VALUES ('A') 
   RETURNING pkey
   )
INSERT INTO bar(foo_fk, other)
SELECT ins.pkey, o.other 
FROM  (
   VALUES
      ('other1'::text)
     ,('other2')
     ,('other3')
   ) o(other)
CROSS  JOIN ins;
于 2013-10-13T11:24:54.963 に答える
2

別のオプションは、使用することですcurrval

INSERT INTO foo
  (name) 
VALUES 
  ('A') ; 

INSERT INTO bar
  (foo_fk,other) 
VALUES 
  (currval('foo_pkey_seq'), 'other1'),
  (currval('foo_pkey_seq'), 'other2'),
  (currval('foo_pkey_seq'), 'other3');

シリアル列の自動作成されたシーケンスには常に名前が付けられます<table>_<column>_seq

編集

より「堅牢な」代替手段はpg_get_serial_sequence、Igor が指摘したように使用することです。

INSERT INTO bar
  (foo_fk,other) 
VALUES 
  (currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other1'),
  (currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other2'),
  (currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other3');
于 2013-10-12T18:56:41.713 に答える