根据插入结果更新表

时间:2018-09-21 08:05:11

标签: sql postgresql sql-update insert-update sql-returning

对于表B,有一个名为a_id的列,它是表A的ID。因此a_id是指向表a的外键,但它只是一个整数列,并且没有设置外约束

对于表B中的每一行,我们需要通过在表A中创建新记录来为a_id列提供一个整数值。

在一个SQL中完成以下所有步骤的目标。

  1. 将所有数据插入表A:

    insert into table A (name) values ('abc'), ('def'), ... returning id

  2. 使用步骤1中返回的ID(每个ID仅应使用一次)对表B中每一行的a_id进行更新

    update table B set a_id = id(from previous insert statement)

尝试过类似的操作

  

更新表B设置a_id =(从ia中选择ia.id
  (插入表A(名称)值('abc'),('def'),...返回ID)为ia)

但这会导致语法错误ERROR: syntax error at or near "into"

如何使用一个SQL做到这一点?

2 个答案:

答案 0 :(得分:0)

如果仅插入一行,则可以使用data modifying CTE

with new_row as (
  insert into table_A (name) values ('abc')
  returning id
)
update table_b
  set a_id = (select id from new_row)
where ?????; -- surely you don't want to update all rows in table_b

但是,如果您在第一条语句中插入多行,则以上将失败

我不清楚,在这种情况下,table_b中的哪些行需要更新。

答案 1 :(得分:0)

这不完全是一个查询,但是如果您真正关心的是避免由于天真的方法对多个查询执行操作而导致的竞争条件/事务隔离异常,那么应该这样做:

-- assign tableA's future primary keys into a_id without 
-- creating entries on tableA, pg_get_serial_sequence()
-- should retrieve tableA's primary key generator
UPDATE tableB
    SET a_id = nextval(pg_get_serial_sequence('tableA', 'id'))
    WHERE a_id IS NULL;

-- insert into tableB, with explicitly specified primary keys, 
-- note that this doesn't increment tableA's sequence as that 
-- has already been done in the previous operation by nextval()
INSERT INTO tableA(id, name)
    SELECT a_id, name FROM tableB;

请注意,您仍应将此内容包装在事务中,以确保如果由于某种原因插入失败,tableB的更新将被回滚。另外,由于上述两个操作是幂等的,因此即使没有事务也可以安全地同时重试。