sql >> Base de Datos >  >> RDS >> PostgreSQL

Combinación de declaraciones INSERT en un CTE de modificación de datos con una expresión CASE

No puede anidar INSERT declaraciones en un CASE expresión. Derivando de lo que veo, este enfoque completamente diferente debería hacerlo:

Supuestos

  • En realidad no necesitas el SELECT externo .

  • dm_name / rm_name se definen como únicos en dm / rm y no vacío (<> '' ). Deberías tener un CHECK restricción para asegurarse.

  • Columna predeterminada para ambos d_id y r_id en z son NULL (predeterminados).

dm_name y rm_name mutuamente excluyentes

Si ambos nunca están presentes al mismo tiempo.

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;

FULL JOIN .. ON FALSE produce una tabla derivada con todas las filas desde d1 y r1 adjunto con NULL para la otra columna respectiva (sin superposición entre los dos). Así que solo necesitamos un INSERT en lugar de dos. Optimización menor.

dm_name y rm_name pueden coexistir

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;

Notas

Ambas versiones también funcionan si ninguna existe.

INSERT no inserta nada si SELECT no devuelve fila(s).

Si tiene que lidiar con el acceso de escritura simultáneo que podría entrar en conflicto con esta operación, la solución rápida sería bloquear las tablas involucradas antes de ejecutar esta instrucción en la misma transacción.