【问题标题】:Can I use return value of INSERT...RETURNING in another INSERT?我可以在另一个 INSERT 中使用 INSERT...RETURNING 的返回值吗?
【发布时间】:2011-09-27 11:24:48
【问题描述】:

这样的事情可能吗?

INSERT INTO Table2 (val)
VALUES ((INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id));

喜欢使用返回值作为值在第二个表中插入一行并引用第一个表?

【问题讨论】:

    标签: postgresql sql-returning


    【解决方案1】:

    您可以从 Postgres 9.1 开始这样做:

    with rows as (
    INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
    )
    INSERT INTO Table2 (val)
    SELECT id
    FROM rows
    

    同时,如果你只对 id 感兴趣,你可以使用触发器来做到这一点:

    create function t1_ins_into_t2()
      returns trigger
    as $$
    begin
      insert into table2 (val) values (new.id);
      return new;
    end;
    $$ language plpgsql;
    
    create trigger t1_ins_into_t2
      after insert on table1
    for each row
    execute procedure t1_ins_into_t2();
    

    【讨论】:

    • 如何在返回的 id 旁边插入值?例如: INSERT INTO TABLE2(val1, val2, val3) (1, 2, SELECT id FROM rows)
    • @MahmoudHanafy:用(some_query returning ...) 替换rows 现在可能可行(尚未尝试)。
    • @MahmoudHanafy:要在返回的 id 旁边插入值,您可以执行以下操作:INSERT INTO TABLE2(val1, val2, val3) SELECT id, 1, 2 FROM rows
    • 点赞!如果第一次插入成功而第二次插入不成功,这是原子意义吗?
    • @PirateApp 刚刚测试过! v12.4。如果第二个 INSERT 失败,则第一个 INSERT 确实会回滚,但会跳过第一个 INSERT 的系列/自动增量
    【解决方案2】:

    这种情况的最佳做法。使用RETURNING … INTO

    INSERT INTO teams VALUES (...) RETURNING id INTO last_id;
    

    注意这是针对 PLPGSQL 的

    【讨论】:

    • 这真的是一回事吗?您链接到的文档的任何部分似乎都没有提到RETURNING ... INTO
    • @Alec:我在this answer 中找到了this documentation
    • @PedroD:确实如此。
    • 非常有用。如果其他读者不清楚,也可以RETURNING col1, col2 INTO var1, var2
    【解决方案3】:
    DO $$
    DECLARE tableId integer;
    BEGIN
      INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id INTO tableId;
      INSERT INTO Table2 (val) VALUES (tableId);
    END $$;
    

    用 psql 测试(10.3,服务器 9.6.8)

    【讨论】:

      【解决方案4】:

      符合 Denis de Bernardy 给出的答案..

      如果您希望之后也返回 id 并希望在 Table2 中插入更多内容:

      with rows as (
      INSERT INTO Table1 (name) VALUES ('a_title') RETURNING id
      )
      INSERT INTO Table2 (val, val2, val3)
      SELECT id, 'val2value', 'val3value'
      FROM rows
      RETURNING val
      

      【讨论】:

        【解决方案5】:

        你可以使用lastval()函数:

        返回最近使用nextval 获得的任何序列的值

        所以是这样的:

        INSERT INTO Table1 (name) VALUES ('a_title');
        INSERT INTO Table2 (val)  VALUES (lastval());
        

        只要没有人在您的 INSERT 之间的任何其他序列(在当前会话中)调用 nextval(),这将正常工作。

        正如下面的Denis 和我在上面警告过的那样,如果在您的INSERT 之间使用nextval() 访问另一个序列,使用lastval() 可能会给您带来麻烦。如果Table1 上的INSERT 触发器在序列上手动调用nextval(),或者更有可能在具有SERIAL or BIGSERIAL 主键的表上执行INSERT,则可能会发生这种情况。如果你想变得非常偏执(一件好事,他们毕竟真的是你的目标),那么你可以使用currval(),但你需要知道相关序列的名称:

        INSERT INTO Table1 (name) VALUES ('a_title');
        INSERT INTO Table2 (val)  VALUES (currval('Table1_id_seq'::regclass));
        

        自动生成的序列通常命名为t_c_seq,其中t 是表名,c 是列名,但您始终可以通过进入psql 并说:

        => \d table_name;
        

        然后查看相关列的默认值,例如:

        id | integer | not null default nextval('people_id_seq'::regclass)
        

        仅供参考:lastval() 或多或少是 MySQL 的 LAST_INSERT_ID 的 PostgreSQL 版本。我之所以提到这一点,是因为很多人比 PostgreSQL 更熟悉 MySQL,所以将 lastval() 链接到熟悉的东西可能会澄清一些事情。

        【讨论】:

        • 最好使用 currval(),以防 table1 上的触发器执行后续插入。
        • @Denis:是的,但是你需要序列的名称。我将对此效果进行一些更新,以涵盖所有基础。
        • LASTVAL() 和 CURRVAL() 都适用于当前数据库连接,不适用于其他连接。其他用户可以同时更新序列,这不会改变您的结果。不要担心其他人,他们永远不会改变你的 LASTVAL 和/的 CURRVAL 结果。在没有 TRANSACTION 的情况下使用连接池时根本不能使用 LASTVAL 和 CURRVAL,这就是问题所在:您无法控制数据库连接。
        • @Frank:是的,它们都是特定于会话的,但lastval 的问题是,在 Table1 上的 AFTER INSERT 触发器背后可能存在基于序列的 INSERT。这将在当前会话中,并且可能会在您不期望时更改lastval()
        【解决方案6】:

        table_ex

        id 默认 nextval('table_id_seq'::regclass),

        camp1 varchar

        camp2 varchar

        INSERT INTO table_ex(camp1,camp2) VALUES ('xxx','123') RETURNING id 
        

        【讨论】:

          猜你喜欢
          • 2019-06-21
          • 1970-01-01
          • 2020-10-31
          • 2010-11-05
          • 2018-08-18
          • 1970-01-01
          • 2023-02-16
          • 1970-01-01
          • 2015-05-14
          相关资源
          最近更新 更多