My question is some kind of extension to Erwin Brandstetter\'s excellent answer in this thread on the correct use of WITH
.
My old query looks like this:
You cannot nest INSERT
statements in a CASE
expression. Deriving from what I see, this completely different approach should do it:
You don't actually need the outer SELECT
.
dm_name
/ rm_name
are defined unique in dm
/ rm
and not empty (<> ''
). You should have a CHECK
constraint to make sure.
Column default for both d_id
and r_id
in z
are NULL (default).
dm_name
and rm_name
mutually exclusiveIf both are never present at the same time.
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;
The FULL JOIN .. ON FALSE
produces a derived table with all rows from d1
and r1
appended with NULL for the respective other column (no overlap between the two). So we just need one INSERT
instead of two. Minor optimization.
dm_name
and rm_name
can coexistWITH 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;
Both versions also work if neither exists.
INSERT
inserts nothing if the SELECT
does not returns row(s).
If you have to deal with concurrent write access that could conflict with this operation the quick fix would be to lock involved tables before you run this statement in the same transaction.