Nie możesz zagnieździć INSERT
instrukcje w CASE
wyrażenie. Wychodząc z tego, co widzę, to zupełnie inne podejście powinno wystarczyć:
Założenia
-
W rzeczywistości nie potrzebujesz zewnętrznego
SELECT
. -
dm_name
/rm_name
są zdefiniowane unikatowo wdm
/rm
i nie puste (<> ''
). Powinieneś miećCHECK
ograniczenie, aby się upewnić. -
Domyślna kolumna dla obu
d_id
ir_id
wz
są NULL (domyślne).
dm_name
i rm_name
wzajemnie wykluczające się
Jeśli oba nie są obecne w tym samym czasie.
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
tworzy tabelę pochodną ze wszystkimi wierszami z d1
i r1
z dodaną wartością NULL dla odpowiedniej drugiej kolumny (brak nakładania się między tymi dwoma). Potrzebujemy więc tylko jednego INSERT
zamiast dwóch. Drobna optymalizacja.
dm_name
i rm_name
może współistnieć
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;
Notatki
Obie wersje działają również, jeśli żadna z nich nie istnieje.
INSERT
nie wstawia niczego, jeśli SELECT
nie zwraca wierszy.
Jeśli masz do czynienia z równoczesnym dostępem do zapisu, który mógłby kolidować z tą operacją, szybką poprawką byłoby zablokowanie zaangażowanych tabel przed uruchomieniem tej instrukcji w tej samej transakcji.