Bạn có thể làm điều này hiệu quả hơn nhiều với một câu lệnh SQL duy nhất với CTE sửa đổi dữ liệu .
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 tại đây
(trang 11)
SQL Fiddle
(trang 9.6)
Điều này phải nhiều nhanh hơn và sạch hơn. Việc tạo vòng lặp là tương đối đắt, việc xử lý ngoại lệ tương đối thậm chí còn đắt hơn.
Quan trọng hơn, các tham chiếu trong lab
được chuyển hướng đến hàng chính tương ứng trong cpt
tự động, chưa có trong mã gốc của bạn. Vì vậy, bạn có thể xóa tất cả các bản sao cùng một lúc .
Bạn vẫn có thể gói nó trong một hàm plpgsql hoặc SQL nếu bạn muốn.
Giải thích
-
Trong gói CTE
plan
đầu tiên , xác định một hàng chính trong mỗi phân vùng với cùng mộtcdesc
. Trong trường hợp của bạn, hàng córecid
tối thiểu . -
Trong CTE thứ 2
upd_lab
chuyển hướng tất cả các hàng tham chiếu bản dupe đến hàng chính trongcpt
. -
Cuối cùng, xóa các lỗi sai, điều này sẽ không làm tăng ngoại lệ vì các hàng tùy thuộc được liên kết với hàng chính còn lại hầu như cùng một lúc.
ON DELETE RESTRICT
Tất cả các CTE và truy vấn chính của một câu lệnh hoạt động trên cùng một ảnh chụp nhanh của các bảng bên dưới, hầu như đồng thời . Họ không thấy tác dụng của nhau đối với các bảng bên dưới:
Người ta có thể mong đợi một ràng buộc FK với ON DELETE RESTRICT
để nâng cao các ngoại lệ bởi vì, [theo tài liệu] [3]:
Tuy nhiên, câu lệnh trên là một lệnh đơn và, [hướng dẫn sử dụng lại] [3]:
Tôi nhấn mạnh đậm. Hoạt động với mặc định ít hạn chế hơn ON DELETE NO ACTION
tất nhiên là quá.
Tuy nhiên, hãy cảnh giác với các giao dịch đồng thời ghi vào cùng một bảng, nhưng đó là sự cân nhắc chung, không cụ thể cho nhiệm vụ này.
Một ngoại lệ áp dụng cho UNIQUE
và PRIMARY KEY
nhưng điều đó không liên quan đến điều này trường hợp: