2017-03-22 40 views
1

我想做一個批量插入事務,但我不太確定如何使用CTE或更有效的方法來做到這一點。這是我到目前爲止有:如何在Postgres中使用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的問題是我不知道如何從第一插入語句個別IDS要插入到其相應的記錄進行了第二條語句'product_id'外鍵。

我將如何構造聲明使其工作?我願意提供替代解決方案,以提供更高效的方法來實現相同的結果。

+0

編輯你的問題,說明你要插入第二個表中的行。 –

+0

@GordonLinoff這些是我想要插入到product_metadata表中的行:(ID爲'Dope product 1',80,'2017-03-21'),(ID爲'Dope product 2',50,'2017-03 -21'),(ID爲'Dope product 3',70,'2017-03-21')。如果您對標題進行了連接(i.title = v.title),您的建議答案是否會起作用?你沒有引用第一次插入的ID,所以我不知道它是否會起作用 – Jamaal

+0

Jamaal:@Gordon在標題上做了JOIN(i.title = v。標題)問題是你不能在第一次插入有兩個相同的項目。我爲解決這個問題做了一個解決方案,但真的很麻煩。我的建議一個接一個插入產品和元數據。 –

回答

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

@TimBiegeleisen我的猜測是'product'中有'product_id' autonumeric,這就是他爲什麼'返回id'的原因。 –

+0

@TimBiegeleisen。 。 。我總是打電話給CTE'我'。我錯過了我留在OP的原名。 –

0

問題是,即使您從第一次插入使用returning id獲得ID,您也無法使用它插入相同的順序,因爲在db中設置的是定義未分類

我按照您的要求做了練習,但您應該重新考慮您的要求,因爲這非常棘手。特別是你需要一個字段來知道元數據順序的部分。

SQL DEMO

  1. 您插入並獲得ID,在這種情況下,你會得到{1,2,3}但ROW_NUMBER您訂購的id這個結果,你可以得到{31,32,33}

  2. 現在,使用和ASIGN的RN知道插入順序{1,2,3}

  3. 現在你的metadata也需要som電子領域,所以你知道的順序。在這種情況下,我創建一個字段insert_order以匹配您要插入的順序。 {100,200,300}
  4. 還爲metadata
  5. 創建一個rn最後,您可以加入兩個表格,因爲您知道兩者的順序。

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

+0

您的解決方案看起來像是有效,但我不認爲它會處理產品表和row_number()的id不同步的場景。例如,如果您刪除產品表中的幾行,並且id現在具有以下序列:1,2,3,6,8,9,似乎不會在row_number上加入這種情況,也可能是我錯了 – Jamaal

+0

是的,那個句柄,首先插入的新ID總是按順序排列的。但即使如此,你也不會用這個值來匹配......你使用從row_number()得到的r來進行匹配。從'1..n'開始,問題是你需要爲元數據添加一些插入順序。也許如果你的日期有'秒',你可以使用它。 –