Du kan gøre dette meget mere effektivt med en enkelt SQL-sætning med datamodificerende CTE'er .
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 her
(s. 11)
SQL Fiddle
(s. 9.6)
Det burde være meget hurtigere og renere. Looping er forholdsvis dyrt, undtagelseshåndtering er forholdsvist endnu dyrere.
Vigtigere er referencer i lab
omdirigeres til den respektive masterrække i cpt
automatisk, hvilket endnu ikke var i din oprindelige kode. Så du kan slette alle duper på én gang .
Du kan stadig pakke dette ind i en plpgsql- eller SQL-funktion, hvis du vil.
Forklaring
-
I den 1. CTE
plan
, identificer en masterrække i hver partition med den sammecdesc
. I dit tilfælde rækken med minimumrecid
. -
I 2. CTE
upd_lab
omdiriger alle rækker, der refererer til en dupe, til masterrækken icpt
. -
Slet endelig duper, hvilket ikke vil give undtagelser, fordi afhængige rækker bliver linket til den resterende masterrække praktisk talt på samme tid.
ON DELETE RESTRICT
Alle CTE'er og hovedforespørgslen i en erklæring operere på det samme øjebliksbillede af underliggende tabeller, praktisk talt samtidigt . De ser ikke hinandens effekter på underliggende tabeller:
Man kunne forvente en FK-begrænsning med ON DELETE RESTRICT
at rejse undtagelser, fordi [pr. dokumentation][3]:
Ovenstående erklæring er dog en enkelt kommando og [manualen igen][3]:
Fed fremhævelse min. Virker for den mindre restriktive standard ON DELETE NO ACTION
også, selvfølgelig.
Men vær på vagt over for samtidige transaktioner, der skriver til de samme tabeller, men det er en generel betragtning, ikke specifik for denne opgave.
En undtagelse gælder for UNIQUE
og PRIMARY KEY
begrænsning, men det vedrører ikke dette sag: