简体   繁体   English

如何从 .sql 脚本文件中获取 postgres 中自动增量列的值?

[英]How to to get the value of an auto increment column in postgres from a .sql script file?

In postgres I have two tables like so在 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
 ); 

What I want to do is to write a .sql script file that does the following我想要做的是编写一个执行以下操作的 .sql 脚本文件

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

which produces the error below in pgAdmin这会在 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

Outside of a stored procedure how do a define a variable that I can use between statements?在存储过程之外,如何定义可以在语句之间使用的变量? Is there some other syntax for being able to insert into bar with the pkey returned from the insert to foo.是否有其他语法可以使用从插入返回的 pkey 插入到 foo.bar 中。

You can combine the queries into one.您可以将查询合并为一个。 Something like:就像是:

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;

Other option - use an anonymous PL/pgSQL block like:其他选项 - 使用匿名 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$$;

You can use lastval() to ...您可以使用lastval()来...

Return the value most recently returned by nextval in the current session.返回当前会话中nextval最近返回的值。

This way you do not need to know the name of the seqence used.这样您就不需要知道所使用的序列的名称。

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

This is safe because you control what you called last in your own session.这是安全的,因为您可以控制自己会话中最后调用的内容。


If you use a writable CTE as proposed by @Ihor , you can still use a short VALUES expression in the 2nd INSERT .如果您使用@Ihor 建议可写 CTE ,您仍然可以在第二个INSERT中使用简短的VALUES表达式。 Combine it with a CROSS JOIN (or append the CTE name after a comma ( , ins ) - same thing):将其与CROSS JOIN结合使用(或在逗号 ( , ins ) 后附加 CTE 名称 - 相同):

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;

Another option is to use currval另一种选择是使用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');

The automatically created sequence for serial columns is always named <table>_<column>_seq为串行列自动创建的序列始终命名为<table>_<column>_seq

Edit :编辑

A more "robust" alternative is to use pg_get_serial_sequence as Igor pointed out.正如 Igor 指出的那样,一个更“强大”的替代方案是使用pg_get_serial_sequence

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');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM