31

Ich möchte Daten in 3 Tabellen mit einer einzigen Abfrage einfügen.
Meine Tabellen sieht aus wie folgt:Einfügen von Daten in 3 Tabellen gleichzeitig mit Postgres

CREATE TABLE sample (
    id  bigserial PRIMARY KEY, 
    lastname varchar(20), 
    firstname varchar(20) 
); 

CREATE TABLE sample1(
    user_id bigserial PRIMARY KEY, 
    sample_id bigint REFERENCES sample, 
    adddetails varchar(20) 
); 

CREATE TABLE sample2(
    id  bigserial PRIMARY KEY, 
    user_id bigint REFERENCES sample1, 
    value varchar(10) 
); 

Ich werde einen Schlüssel im Gegenzug für jede Einfügung bekommen und ich brauche den Schlüssel in der nächsten Tabelle einzufügen. sie nur Werte zurück zu mir

insert into sample(firstname,lastname) values('fai55','shaggk') RETURNING id; 
insert into sample1(sample_id, adddetails) values($id,'ss') RETURNING user_id; 
insert into sample2(user_id, value) values($id,'ss') RETURNING id; 

Aber wenn ich einzelne Abfragen ausführen und ich kann sie nicht sofort in der nächsten Abfrage wiederverwenden:
Meine Abfrage ist.

Wie erreichen?

Antwort

1

Sie könnten einen After-Insert-Trigger für die Beispieltabelle erstellen, um sie in die anderen beiden Tabellen einzufügen.

Das einzige Problem, das ich dabei sehe, ist, dass Sie keine Möglichkeit haben, Adddetails einzufügen, es wird immer leer sein oder in diesem Fall ss. Es gibt keine Möglichkeit, eine Spalte in die Probe einzufügen, die nicht in der Probentabelle vorhanden ist, so dass Sie sie nicht zusammen mit dem Original einfügen können.

Eine andere Option wäre, eine gespeicherte Prozedur zum Ausführen Ihrer Einsätze zu erstellen.

Sie haben die Frage taged mysql und postgressql welche Datenbank sprechen wir hier?

8

So etwas wie dies

with first_insert as (
    insert into sample(firstname,lastname) 
    values('fai55','shaggk') 
    RETURNING id 
), 
second_insert as (
    insert into sample1(id ,adddetails) 
    values 
    ((select id from first_insert), 'ss') 
    RETURNING user_id 
) 
insert into sample2 (id ,adddetails) 
values 
((select user_id from first_insert), 'ss'); 

Da die erzeugte ID aus dem Einsatz in sample2 ist nicht erforderlich, Ich entfernte die returning Klausel aus dem letzten Einsatz.

60

Verwendung data-modifying CTEs:

WITH ins1 AS (
    INSERT INTO sample(firstname, lastname) 
    VALUES ('fai55', 'shaggk') 
-- ON  CONFLICT DO NOTHING    -- optional addition in Postgres 9.5+ 
    RETURNING id AS user_id 
    ) 
, ins2 AS (
    INSERT INTO sample1 (user_id, adddetails) 
    SELECT user_id, 'ss' FROM ins1 
    -- RETURNING user_id      -- only if used in turn 
    ) 
INSERT INTO sample2 (user_id, value)   -- same here 
SELECT user_id, 'ss' FROM ins1; 

Jeder Einsatz ist abhängig von dem anderen. SELECT anstelle von VALUES stellt sicher, dass nichts in Hilfstabellen eingefügt wird, wenn von der vorherigen Einfügung keine Zeile zurückgegeben wird. (Verwandte: Klausel in Postgres 9.5 +)
Es ist auch ein bisschen kürzer und schneller so.


Normalerweise ist es bequemer, Reihen vollständige Daten liefern an einem Ort:

WITH data(firstname, lastname, adddetails, value) AS (
    VALUES         -- provide data here 
     (text 'fai55', text 'shaggk', text 'ss', text 'ss2') -- see below 
     -- more?       -- works for multiple input rows 
    ) 
, ins1 AS (
    INSERT INTO sample (firstname, lastname) 
    SELECT firstname, lastname FROM data -- DISTINCT? see below 
    ON  CONFLICT DO NOTHING    -- required UNIQUE constraint 
    RETURNING firstname, lastname, id AS sample_id 
    ) 
, ins2 AS (
    INSERT INTO sample1 (sample_id, adddetails) 
    SELECT sample_id, adddetails 
    FROM data 
    JOIN ins1 USING (firstname, lastname) 
    RETURNING sample_id, user_id 
    ) 
INSERT INTO sample2 (user_id, value) 
SELECT user_id, value 
FROM data 
JOIN ins1 USING (firstname, lastname) 
JOIN ins2 USING (sample_id); 

Sie expliziten Typen benötigen wirft in einem separaten VALUES Ausdruck (im Gegensatz zu einem VALUES Ausdruck An ein INSERT angehängt, wobei Datentypen von der Zieltabelle abgeleitet werden

Wenn mehrere Zeilen mit identi cal (firstname, lastname), müssen Sie für den ersten Einsatz Duplikate falten:

... 
INSERT INTO sample (firstname, lastname) 
SELECT DISTINCT firstname, lastname FROM data 
... 

Sie eine (temporäre) Tabelle als Datenquelle anstelle des data CTE nutzen könnten.

Verwandte, mit mehr Details:

+0

thanx für die Wiedergabe kann ich Transaktion Roll-out hinzufügen, wenn eine Einfügung fehlschlagen .ja auftritt wie kann ich – Faisal

+1

Dies ist eine einzelne SQL-Anweisung. Man kann mehrere Anweisungen in einer einzigen Transaktion bündeln, aber man kann diese nicht aufteilen. Auch was Denis in seinem Kommentar sagt. Und ich habe einige Links zu meiner Antwort hinzugefügt. –

+0

aber können Sie eine SELECT innerhalb der CTE haben, und dann sofort nach der Verwendung mit einem INSERT? – mmcrae

4

Normalerweise würden Sie eine Transaktion verwenden, um komplizierte Abfragen zu vermeiden zu schreiben.

http://www.postgresql.org/docs/current/static/sql-begin.html

http://dev.mysql.com/doc/refman/5.7/en/commit.html

Sie auch einen CTE, vorausgesetzt, Ihr Postgres-Tag ist richtig nutzen könnten. Zum Beispiel:

with sample_ids as (
    insert into sample(firstname, lastname) 
    values('fai55','shaggk') 
    RETURNING id 
), sample1_ids as (
    insert into sample1(id, adddetails) 
    select id,'ss' 
    from sample_ids 
    RETURNING id, user_id 
) 
insert into sample2(id, user_id, value) 
select id, user_id, 'val' 
from sample1_ids 
RETURNING id, user_id; 
+0

Danke wie würde ich Erreiche die Transaktion in dieser Abfrage, wenn irgendeine Einfügung fehlschlägt, könnte ich rollback machen – Faisal

+0

Dann beginnst du alles wieder, nachdem die Abfragen natürlich korrigiert wurden, da die gesamte Transaktion (oder die Cte) zurückgerollt werden würde. Übrigens, wenn Ihre Beilagen gelegentlich ausfallen, tun Sie wahrscheinlich etwas falsch. Der einzige Fall, in dem ein Insert fehlschlägt, ist ein Upsert-Szenario, in dem während konkurrierender Transaktionen doppelte eindeutige Schlüssel verwendet werden. Selbst dann könnten Sie eine Advisory-Sperre oder eine Tabellensperre erhalten, wenn Sie kugelsicher sein müssen. –

Verwandte Themen