Můžete to udělat mnohem efektivněji pomocí jediného příkazu SQL s CTE upravující data .
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 zde
(str. 11)
SQL Fiddle
(str. 9.6)
To by mělo být hodně rychlejší a čistší. Opakování je poměrně drahé, zpracování výjimek je poměrně ještě dražší.
Důležitější je, odkazy v lab
jsou přesměrováni na příslušný hlavní řádek v cpt
automaticky, což ještě nebylo ve vašem původním kódu. Můžete tedy smazat všechny dupy najednou .
Stále to můžete zabalit do funkce plpgsql nebo SQL, pokud chcete.
Vysvětlení
-
V 1.
plan
CTE , identifikujte hlavní řádek v každém oddílu se stejnýmcdesc
. Ve vašem případě řádek s minimemrecid
. -
Ve 2. CTE
upd_lab
přesměrovat všechny řádky odkazující na dupe na hlavní řádek vcpt
. -
Nakonec smažte dupy, což nebude vyvolávat výjimky, protože závislé řádky jsou propojeny se zbývajícím hlavním řádkem prakticky současně.
ON DELETE RESTRICT
Všechny CTE a hlavní dotaz výkazu pracovat na stejném snímku podkladových tabulek, prakticky současně . Nevidí vzájemný vliv na podkladové tabulky:
Dalo by se očekávat omezení FK s ON DELETE RESTRICT
vyvolat výjimky, protože [podle dokumentace][3]:
Výše uvedený příkaz je však jediným příkazem a [znovu manuál][3]:
Odvážný důraz můj. Funguje pro méně omezující výchozí ON DELETE NO ACTION
také, samozřejmě.
Dávejte si ale pozor na souběžné transakce zapisující do stejných tabulek, ale to je obecná úvaha, nikoli specifická pro tento úkol.
Výjimka platí pro UNIQUE
a PRIMARY KEY
omezení, ale to se tohoto netýká případ: