如何在Postgres中使用CTE插入带有外键的多行?

时间:2017-03-22 01:10:35

标签: sql postgresql

我想进行批量插入事务,但我不太确定如何使用CTE或更有效的方法来执行此操作。这就是我到目前为止所做的:

with bulky as (
    insert into products (title, description, price) 
                  values ('Dope product 1', 'Buy diz', 9.99), 
                         ('Dope product 2', 'Buy diz', 8.99), 
                         ('Dope product 2', 'Buy diz', 7.99) 
                  returning id
) 
insert into product_metadata (product_id, sales_volume, date) 
                       values (???, 80, '2017-03-21'), 
                              (???, 50, '2017-03-21'), 
                              (???, 70, '2017-03-21');

我的CTE的问题是我不知道如何将第一个插入语句中的单个ID插入到第二个语句的相应记录中,该语句具有' product_id'外键。

我如何构建声明以使其工作?我愿意提供替代解决方案,以提供更有效的方法来实现相同的结果。

2 个答案:

答案 0 :(得分:2)

以下是对您想要做的事情的合理解释:

with i as (
      insert into products (title, description, price)
          values ('Dope product 1', 'Buy diz', 9.99),
                 ('Dope product 2', 'Buy diz', 8.99),
                 ('Dope product 3', 'Buy diz', 7.99)
          returning *
     ) 
insert into product_metadata (product_id, sales_volume, date)
    select i.product_id, v.sales_volume, v.date
    from (values ('Dope product 1', 80, '2017-03-21'),
                 ('Dope product 2', 50, '2017-03-21'), 
                 ('Dope product 3', 70, '2017-03-21')
         ) v(title, sales_volume, date) join
         i
         on i.title = v.title;

基本答案为"使用returning *并使用join获取值"。我需要更改标题,使它们独一无二。

答案 1 :(得分:0)

问题是即使你使用returning id从第一个插入中获取id,也无法使用它来插入相同的顺序,因为db中的set是定义未排序的

我做了符合你要求的练习,但是你应该重新考虑你的要求,因为这非常棘手。特别是您需要字段来了解元数据顺序的部分。

<强> SQL DEMO

  1. 您插入并获取了ID,在这种情况下,您获得了{1,2,3},但您可以获得{31,32,33}

  2. 现在使用row_number,您可以按id对结果进行排序并指定一个rn以了解插入顺序{1,2,3}

  3. 现在您的metadata也需要一些字段,以便您了解订单。在这种情况下,我创建一个字段insert_order以匹配您插入的顺序。 {100,200,300}
  4. 同时为metadata
  5. 创建一个rn
  6. 最后,您可以加入两个表,因为您知道两者的顺序。
  7. with prod as (         
        insert into products (title, description, price) 
                      values ('Dope product 1', 'Buy diz', 9.99), 
                             ('Dope product 2', 'Buy diz', 8.99), 
                             ('Dope product 2', 'Buy diz', 7.99) 
                      returning id
    ), prod_order as (
           SELECT id, row_number() over (order by id) as rn
           FROM prod
    ), metadata as (
        SELECT *, row_number() over (order by insert_order) as rn
        FROM (values (100, 80, '2017-03-21'::timestamp),
                     (200, 50, '2017-03-21'::timestamp), 
                     (300, 70, '2017-03-21'::timestamp)
              ) t (insert_order, sales_volume, date) 
    )    
    INSERT INTO product_metadata
    SELECT po."id", m."sales_volume", m."date"
    FROM prod_order po
    JOIN metadata m 
      ON po.rn = m.rn;
    

    <强>输出

    enter image description here