Du kan göra detta mycket mer effektivt med en enskild SQL-sats med datamodifierande 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<>fiol här
(sid 11)
SQL Fiddle
(sid 9.6)
Det här borde vara mycket snabbare och renare. Looping är jämförelsevis dyrt, undantagshantering är jämförelsevis ännu dyrare.
Och ännu viktigare, referenser i lab
omdirigeras till respektive huvudrad i cpt
automatiskt, vilket inte fanns i din ursprungliga kod ännu. Så du kan ta bort alla duper på en gång .
Du kan fortfarande slå in detta i en plpgsql- eller SQL-funktion om du vill.
Förklaring
-
I den första CTE
plan
, identifiera en masterrad i varje partition med sammacdesc
. I ditt fall raden med minstarecid
. -
I den andra CTE
upd_lab
omdirigera alla rader som hänvisar till en dupe till huvudraden icpt
. -
Slutligen, ta bort duper, vilket inte kommer att skapa undantag eftersom beroende rader kopplas till den återstående masterraden praktiskt taget samtidigt.
ON DELETE RESTRICT
Alla CTE:er och huvudfrågan i ett uttalande arbeta på samma ögonblicksbild av underliggande tabeller, praktiskt taget samtidigt . De ser inte varandras effekter på underliggande tabeller:
Man kan förvänta sig en FK-begränsning med ON DELETE RESTRICT
att ta upp undantag eftersom, [per dokumentation][3]:
Men uttalandet ovan är ett enkelt kommando och, [manualen igen][3]:
Djärv betoning min. Fungerar för den mindre restriktiva standarden ON DELETE NO ACTION
också såklart.
Men var försiktig med samtidiga transaktioner som skrivs till samma tabeller, men det är ett allmänt övervägande, inte specifikt för denna uppgift.
Ett undantag gäller för UNIQUE
och PRIMARY KEY
begränsning, men det gäller inte det här fall: