PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Combinaison d'instructions INSERT dans un CTE de modification de données avec une expression CASE

Vous ne pouvez pas imbriquer INSERT instructions dans un CASE expression. D'après ce que je vois, cette approche complètement différente devrait le faire :

Hypothèses

  • Vous n'avez pas réellement besoin du SELECT externe .

  • dm_name / rm_name sont définis uniques dans dm / rm et non vide (<> '' ). Vous devriez avoir un CHECK contrainte pour s'en assurer.

  • Colonne par défaut pour les deux d_id et r_id en z sont NULL (par défaut).

dm_name et rm_name mutuellement exclusif

Si les deux ne sont jamais présents en même temps.

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;

Le FULL JOIN .. ON FALSE produit une table dérivée avec toutes les lignes de d1 et r1 ajouté avec NULL pour l'autre colonne respective (pas de chevauchement entre les deux). Nous avons donc juste besoin d'un INSERT au lieu de deux. Optimisation mineure.

dm_name et rm_name peuvent coexister

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;

Remarques

Les deux versions fonctionnent également si aucune n'existe.

INSERT n'insère rien si le SELECT ne renvoie pas de ligne(s).

Si vous devez gérer un accès en écriture concurrent qui pourrait entrer en conflit avec cette opération, la solution rapide consisterait à verrouiller les tables impliquées avant d'exécuter cette instruction dans la même transaction.