2017-03-22 3 views
1

Ich möchte eine Bulk-Insert-Transaktion durchführen, aber ich bin mir nicht sicher, wie dies mit CTEs oder einer effizienteren Methode zu tun ist. Das ist, was ich habe, so weit:Wie füge ich mehrere Zeilen mit einem Fremdschlüssel mit einem CTE in Postgres ein?

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'); 

Das Problem mit meinem CTE ist, ich weiß nicht, wie die einzelnen IDs von der ersten Insert-Anweisung zu bekommen, um für die zweite Anweisung in ihre entsprechenden Datensätze eingefügt werden, hat Der Fremdschlüssel 'product_id'.

Wie würde ich die Anweisung konstruieren, damit sie funktioniert? Ich bin offen für alternative Lösungen, die eine effizientere Methode bieten, um das gleiche Ergebnis zu erzielen.

+0

Bearbeiten Sie Ihre Frage und zeigen die Zeilen, die Sie in die zweite Tabelle eingefügt werden sollen. –

+0

@GordonLinoff Dies sind die Zeilen, die ich in die Tabelle product_metadata einfügen möchte: (ID FOR 'Dope product 1', 80, '2017-03-21'), (ID FÜR 'Dope product 2', 50, '2017-03 -21 '), (ID FOR' Dope product 3 ', 70,' 2017-03-21 '). Würde Ihre vorgeschlagene Antwort funktionieren, wenn Sie den Titel beitreten (i.title = v.title)? Du verweisst nicht die ID von der ersten Einfügung, also bin ich nicht sicher, ob es funktionieren würde – Jamaal

+0

Jamaal: @Gordon macht das 'JOIN' auf dem Titel (i.title = v.Titel) Das Problem ist, dass Sie nicht zwei der gleichen Elemente auf der ersten einfügen können. Ich habe eine Lösung gefunden, um das zu lösen, aber es ist wirklich chaotisch. Mein Vorschlag: Fügen Sie Produkt und Metadaten einzeln ein. –

Antwort

2

Im Folgenden ist eine vernünftige Interpretation dessen, was Sie tun möchten:

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; 

Die grundlegende Antwort ist „returning * verwenden und eine join verwenden, um die Werte zu erhalten“. Ich musste die Titel ändern, damit sie einzigartig sind.

+1

@TimBiegeleisen Meine Vermutung ist, gibt es 'product_id' autonumeric in' products' das ist, warum er 'id zurückgibt' –

+0

@TimBiegeleisen. . . Ich nenne das immer CTE 'i'. Ich habe verpasst, dass ich den ursprünglichen OP-Namen angegeben habe. –

0

Das Problem ist, auch wenn Sie die ID aus dem ersten Einsatz erhalten mit returning id gibt es keine Möglichkeit, es auf der gleichen Reihenfolge einfügen können, da Satz in db von Definition unsortiert sind.

Ich habe die Übung gemacht, um Ihre Anforderung zu erfüllen, aber Sie sollten Ihre Anforderung überdenken, weil dies sehr schwierig ist. Speziell der Teil, wo Sie ein Feld benötigen, um die Reihenfolge der Metadaten zu kennen.

SQL DEMO

  1. Sie fügen und die ID erhalten, in diesem Fall, dass Sie {1,2,3} erhalten, aber Sie können mit {31,32,33}

  2. Jetzt erhalten row_number Sie das Ergebnis durch id bestellen und asign ein rn Um die Reihenfolge der Bestellung zu kennen {1,2,3}

  3. Jetzt brauchen Sie auch Ihre metadata som e Feld, damit Sie die Reihenfolge kennen. In diesem Fall erstelle ich ein Feld insert_order, das der Reihenfolge entspricht, in der Sie einfügen. {100,200,300}
  4. Erstellen Sie auch eine RN für metadata
  5. Schließlich können Sie beide Tabellen beitreten, weil Sie die Reihenfolge der beiden kennen.

.

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; 

OUTPUT

enter image description here

+0

Ihre Lösung sieht so aus, als ob sie funktioniert, aber ich denke nicht, dass sie das Szenario behandeln würde, in dem die IDs der products table und row_number() nicht synchron sind. Zum Beispiel, wenn Sie ein paar Zeilen in der Produkttabelle löschen und die IDs nun folgende Sequenz haben: 1, 2, 3, 6, 8, 9, scheint es nicht so zu sein, als würde die Verbindung zu row_number in diesem Fall funktionieren, oder vielleicht ich bin falsch – Jamaal

+0

Ja, das handle, zuerst die neue ID aus einfügen sind immer in der Reihenfolge. Aber selbst das ... du verwendest diesen Wert nicht um zu passen ... du verwendest den rn, den du von 'row_number()' bekommst, um die Übereinstimmung zu machen. Und das geht von '1..n', das Problem ist, dass Sie die Einfügereihenfolge für die Metadaten etwas hinzufügen müssen. Vielleicht, wenn Ihr Datum "Sekunden" hat, könnten Sie es verwenden. –

Verwandte Themen