PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Combinazione di istruzioni INSERT in un CTE di modifica dei dati con un'espressione CASE

Non puoi annidare INSERT dichiarazioni in un CASE espressione. Derivato da quello che vedo, questo approccio completamente diverso dovrebbe farlo:

Ipotesi

  • In realtà non hai bisogno del SELECT esterno .

  • dm_name / rm_name sono definiti univoci in dm / rm e non vuoto (<> '' ). Dovresti avere un CHECK vincolo per essere sicuro.

  • Colonna predefinita per entrambi d_id e r_id in z sono NULL (predefinito).

dm_name e rm_name si escludono a vicenda

Se entrambi non sono mai presenti contemporaneamente.

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;

Il FULL JOIN .. ON FALSE produce una tabella derivata con tutte le righe da d1 e r1 aggiunto con NULL per la rispettiva altra colonna (nessuna sovrapposizione tra le due). Quindi abbiamo solo bisogno di un INSERT invece di due. Ottimizzazione minore.

dm_name e rm_name possono coesistere

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;

Note

Entrambe le versioni funzionano anche se nessuna delle due esiste.

INSERT non inserisce nulla se il SELECT non restituisce riga/i.

Se devi gestire un accesso in scrittura simultaneo che potrebbe entrare in conflitto con questa operazione, la soluzione rapida sarebbe bloccare le tabelle coinvolte prima di eseguire questa istruzione nella stessa transazione.