PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Kombinieren von INSERT-Anweisungen in einem datenmodifizierenden CTE mit einem CASE-Ausdruck

Sie können INSERT nicht verschachteln Anweisungen in einem CASE Ausdruck. Abgeleitet von dem, was ich sehe, sollte dieser völlig andere Ansatz es tun:

Annahmen

  • Das äußere SELECT brauchen Sie eigentlich nicht .

  • dm_name / rm_name sind eindeutig in dm definiert / rm und nicht leer (<> '' ). Sie sollten einen CHECK haben Einschränkung, um sicherzustellen.

  • Spaltenvorgabe für beide d_id und r_id in z sind NULL (Standard).

dm_name und rm_name sich gegenseitig ausschließen

Wenn beide nie gleichzeitig vorhanden sind.

WITH d1 AS (
   INSERT INTO d (dm_id)
   SELECT dm.dm_id 
   FROM   import
   JOIN   dm USING (dm_name)
   RETURNING d_id
   )
, r1 AS (
   INSERT INTO r (rm_id)
   SELECT rm.rm_id 
   FROM   import
   JOIN   rm USING (rm_name)
   RETURNING r_id
   )
, z1 AS (
   INSERT INTO z (d_id, r_id)
   SELECT d_id, r_id
   FROM d1 FULL JOIN r1 ON FALSE
   RETURNING z_id
   )
INSERT INTO port (z_id)
SELECT z_id
FROM   z1;

Der FULL JOIN .. ON FALSE erzeugt eine abgeleitete Tabelle mit allen Zeilen aus d1 und r1 angehängt mit NULL für die jeweils andere Spalte (keine Überschneidung zwischen beiden). Wir brauchen also nur ein INSERT statt zwei. Kleinere Optimierung.

dm_name und rm_name koexistieren

WITH i AS (
   SELECT dm.dm_id, rm.rm_id
   FROM   import
   LEFT   JOIN dm USING (dm_name)
   LEFT   JOIN rm USING (rm_name)
   )
, d1 AS (
   INSERT INTO d (dm_id)
   SELECT dm_id FROM i WHERE dm_id IS NOT NULL
   RETURNING dm_id, d_id
   )
, r1 AS (
   INSERT INTO r (rm_id)
   SELECT rm_id FROM i WHERE rm_id IS NOT NULL
   RETURNING rm_id, r_id
   )
, z1 AS (
   INSERT INTO z (d_id, r_id)
   SELECT d1.d_id, r1.r_id
   FROM   i
   LEFT   JOIN d1 USING (dm_id)
   LEFT   JOIN r1 USING (rm_id)
   WHERE  d1.dm_id IS NOT NULL OR
          r1.rm_id IS NOT NULL
   RETURNING z_id
   )
INSERT INTO port (z_id)
SELECT z_id FROM z1;

Notizen

Beide Versionen funktionieren auch, wenn keine vorhanden ist.

INSERT fügt nichts ein, wenn SELECT gibt keine Zeile(n) zurück.

Wenn Sie mit gleichzeitigem Schreibzugriff umgehen müssen, der mit dieser Operation in Konflikt geraten könnte, besteht die schnelle Lösung darin, die betroffenen Tabellen zu sperren, bevor Sie diese Anweisung in derselben Transaktion ausführen.