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.
planCTE , identifikujte hlavní řádek v každém oddílu se stejnýmcdesc. Ve vašem případě řádek s minimemrecid. -
Ve 2. CTE
upd_labpř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: