从另一个 table 插入值并使用返回值更新原始 table

Insert values from another table and update original table with returning values

我是 PostgreSQL(甚至是 Whosebug)的新手。
比如说,我有两个 tables OrderDelivery:

Order

id     product      address           delivery_id
--------------------------------------------------
1      apple        mac street        (null)
3      coffee       java island       (null)
4      window       micro street      (null)

Delivery

id     address
----------------

Delivery.idOrder.id 是自动递增的序列列。
table Delivery 当前为空。

我想将 Order.address 移动到 Delivery.address 并将其 Delivery.id 移动到 Order.delivery_id 以达到此状态:

Order

id     product      address           delivery_id
--------------------------------------------------
1      apple        mac street        1
5      coffee       java island       2
7      window       micro street      3

Delivery

id     address
---------------------
1      mac street
2      java island
3      micro street

然后我将删除 Order.address

我为 Oracle 找到了类似的问题,但未能将其转换为 PostgreSQL:

我仍然认为应该可以在 Postgres 中使用带有 RETURNING 子句的普通 SQL 语句和随后的 INSERT

我试过这个(以及一些变体):

WITH ids AS (
    INSERT INTO Delivery (address)
    SELECT address
    FROM Order
    RETURNING Delivery.id AS d_id, Order.id AS o_id
)
UPDATE Order
SET Delivery_id = d_id
FROM ids
WHERE Order.id = ids.o_id;

最近一次尝试失败:

ERROR: missing FROM-clause entry for table "Delivery" LINE 1: ...address Order RETURNING Delivery.id...

如何正确执行此操作?

首先,ORDER是一个reserved word。不要将其用作标识符。假设 orders 为 table nae。

WITH ids AS (
   INSERT INTO delivery (address)
   SELECT DISTINCT address
   FROM   orders
   ORDER  BY address -- optional
   RETURNING *
   )
UPDATE orders o
SET    delivery_id = i.id
FROM   ids i
WHERE  o.address = i.address;

您必须考虑 order.address 中可能的重复项。 SELECT DISTINCT 生成唯一地址。

在外部 UPDATE 我们现在可以在 address 上重新加入,因为 delivery.address 是独一无二的。您可能应该在该声明之外保持这种方式,并在该列上添加一个 UNIQUE constraint

有效地导致 deliveryorders 之间的一对多关系。 delivery 中的一行在 orders 中可以有许多对应的行。考虑通过相应地添加 FOREIGN KEY constraint 来强制实施。

此语句享有从空 delivery table 开始的好处。如果 delivery 不为空,我们将不得不使用 UPSERT 而不是 INSERT。参见:

相关:

  • Insert data in 3 tables at a time using Postgres

关于您收到的错误消息的原因:

如果可以,只使用合法的小写标识符。参见:

  • Are PostgreSQL column names case-sensitive?

您不能在 CTE 查询的 RETURNING 子句中 return 来自 FROM 关系的列。您必须在游标中管理它,或者将 order_id 列添加到 Delivery table,像这样:

ALTER TABLE Delivery ADD COLUMNN order_id INTEGER:

INSERT INTO Delivery (address, order_id)
    SELECT address, id
    FROM Order
;

WITH q_ids AS
(
    SELECT id, order_id
    FROM Delivery
)
UPDATE Order
SET delivery_id = q_ids.id
FROM q_ids
WHERE Order.id = q_ids.order_id;