sql >> Database >  >> RDS >> PostgreSQL

Combineren van INSERT-instructies in een gegevensmodificerende CTE met een CASE-expressie

U kunt INSERT niet nesten uitspraken in een CASE uitdrukking. Afgeleid van wat ik zie, zou deze totaal andere benadering het moeten doen:

Aannames

  • Je hebt de buitenste SELECT eigenlijk niet nodig .

  • dm_name / rm_name zijn uniek gedefinieerd in dm / rm en niet leeg (<> '' ). U moet een CHECK . hebben beperking om zeker te zijn.

  • Kolomstandaard voor beide d_id en r_id in z zijn NULL (standaard).

dm_name en rm_name elkaar uitsluiten

Als beide nooit tegelijkertijd aanwezig zijn.

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;

De FULL JOIN .. ON FALSE produceert een afgeleide tabel met alle rijen van d1 en r1 toegevoegd met NULL voor de respectieve andere kolom (geen overlap tussen de twee). Dus we hebben er maar één nodig INSERT in plaats van twee. Kleine optimalisatie.

dm_name en rm_name kunnen naast elkaar bestaan

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;

Opmerkingen

Beide versies werken ook als geen van beide bestaat.

INSERT voegt niets in als de SELECT retourneert geen rij(en).

Als u te maken krijgt met gelijktijdige schrijftoegang die in strijd zou kunnen zijn met deze bewerking, is de snelle oplossing om de betrokken tabellen te vergrendelen voordat u deze instructie in dezelfde transactie uitvoert.




  1. INNER JOIN vs LEFT JOIN prestaties in SQL Server

  2. MySQL match() against() - volgorde op relevantie en kolom?

  3. Hoe een Foreign key Constraint toe te voegen aan een bestaande tabel in SQL Server - SQL Server / TSQL Tutorial Part 68

  4. Hoe u alle weergaven in een PostgreSQL-database kunt weergeven