0

在 postgres 我有两个这样的表

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

在存储过程之外,如何定义可以在语句之间使用的变量?是否有其他语法可以使用从插入返回的 pkey 插入到 foo.bar 中。

4

3 回答 3

5

您可以将查询合并为一个。就像是:

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。您仍然可以在第二个 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 回答