PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Combinando instruções INSERT em um CTE de modificação de dados com uma expressão CASE


Você não pode aninhar INSERT instruções em um CASE expressão. Derivando do que vejo, essa abordagem completamente diferente deve fazê-lo:

Suposições


  • Na verdade, você não precisa do SELECT externo .

  • dm_name / rm_name são definidos como únicos em dm / rm e não vazio (<> '' ). Você deve ter um CHECK restrição para ter certeza.

  • Coluna padrão para ambos d_id e r_id em z são NULL (padrão).

dm_name e rm_name mutuamente exclusivos


Se ambos nunca estiverem presentes ao mesmo tempo.
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;

O FULL JOIN .. ON FALSE produz uma tabela derivada com todas as linhas de d1 e r1 anexado com NULL para a respectiva outra coluna (sem sobreposição entre os dois). Então, só precisamos de um INSERT em vez de dois. Otimização menor.

dm_name e rm_name podem 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;

Observações


Ambas as versões também funcionam se nenhuma delas existir.

INSERT não insere nada se o SELECT não retorna linha(s).

Se você tiver que lidar com acesso de gravação simultâneo que possa entrar em conflito com essa operação, a solução rápida seria bloquear as tabelas envolvidas antes de executar essa instrução na mesma transação.