Możesz to zrobić znacznie wydajniej za pomocą pojedynczej instrukcji SQL z CTE modyfikacji danych .
WITH plan AS (
SELECT *
FROM (
SELECT recid, min(recid) OVER (PARTITION BY cdesc) AS master_recid
FROM cpt
) sub
WHERE recid <> master_recid -- ... <> self
)
, upd_lab AS (
UPDATE lab l
SET cpt_recid = p.master_recid -- link to master recid ...
FROM plan p
WHERE l.cpt_recid = p.recid
)
DELETE FROM cpt c
USING plan p
WHERE c.recid = p.recid
RETURNING c.recid;
db<>fiddle tutaj
(str. 11)
Skrzypce SQL
(str. 9.6)
Powinno to być dużo szybciej i czyściej. Zapętlanie jest stosunkowo drogie, obsługa wyjątków jest stosunkowo jeszcze droższa.
Co ważniejsze, referencje w lab
są przekierowywane do odpowiedniego wiersza głównego w cpt
automatycznie, czego jeszcze nie było w oryginalnym kodzie. Możesz więc usunąć wszystkie duplikaty naraz .
Jeśli chcesz, nadal możesz umieścić to w funkcji plpgsql lub SQL.
Wyjaśnienie
-
W 1. CTE
plan
, zidentyfikuj wiersz główny w każdej partycji z tym samymcdesc
. W Twoim przypadku wiersz z minimalnymrecid
. -
W drugim CTE
upd_lab
przekieruj wszystkie wiersze odwołujące się do duplikatu do wiersza głównego wcpt
. -
Na koniec usuń duplikaty, co nie spowoduje wyjątków, ponieważ zależne wiersze są połączone z pozostałym wierszem głównym praktycznie w tym samym czasie.
ON DELETE RESTRICT
Wszystkie CTE i główne zapytanie wyciągu działają na tej samej migawce tabel bazowych, praktycznie równocześnie . Nie widzą efektów innych w tabelach poniżej:
Można by oczekiwać ograniczenia FK z ON DELETE RESTRICT
zgłaszać wyjątki, ponieważ [w dokumentacji][3]:
Jednak powyższe stwierdzenie jest pojedynczym poleceniem i [instrukcja ponownie][3]:
Moje odważne podkreślenie. Działa dla mniej restrykcyjnego domyślnego ON DELETE NO ACTION
oczywiście też.
Uważaj jednak na współbieżne transakcje zapisywania do tych samych tabel, ale jest to ogólna uwaga, a nie specyficzna dla tego zadania.
Wyjątek dotyczy UNIQUE
i PRIMARY KEY
ograniczenie, ale to nie dotyczy tego sprawa: