【问题标题】:Insert values from another table and update original table with returning values从另一个表中插入值并使用返回值更新原始表
【发布时间】:2021-07-25 10:50:51
【问题描述】:

我是 PostgreSQL(甚至是 Stackoverflow)的新手。
说,我有两张桌子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 是自动递增的串行列。
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 子句和以下 INSERT 的普通 SQL 语句。

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

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;

最近一次尝试失败:

错误:表“Delivery”第 1 行缺少 FROM 子句条目:...address Order RETURNING Delivery.id...

如何正确地做到这一点?

【问题讨论】:

    标签: sql postgresql common-table-expression sql-returning


    【解决方案1】:

    您不能从 CTE 查询的 RETURNING 子句中的 FROM 关系返回列。您必须在游标中进行管理,或者将 order_id 列添加到 Delivery 表中,如下所示:

    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;
    

    【讨论】:

      【解决方案2】:

      首先,ORDER 是一个reserved word。不要将其用作标识符。假设 orders 改为表 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 表开始。如果delivery 不为空,我们将不得不使用UPSERT 而不是INSERT。见:

      相关:

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

      尽可能使用合法的小写标识符。见:

      【讨论】:

      • 我认为如果地址不能保证是唯一的,这个逻辑就会失败?
      • @DonR:此语句旨在处理重复地址。你认为它会如何失败?
      • 我可能是错误地假设 OP 想要 1-1 关系;在继续进行该假设之前,我应该要求澄清。
      • 事实上,我打算建立 1-1 关系,你正确地假设了@DonR。因为真正的Delivery 表中有更多的列。我的错。我必须进一步澄清我的问题。
      • 无论如何,@ErwinBrandstetter 的回答也非常有帮助。如果有人看到这篇文章并正在寻找衡量一对多关系的方法,这将是他/她的最佳答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多