假設所有外鍵都有適當的約束,是否有一個簡單的SQL語句來刪除在數據庫中任何地方沒有引用的行?SQL刪除孤兒
像delete from the_table
那樣簡單,只需跳過任何帶有子記錄的行?
我試圖避免手動循環表或添加類似where the_SK not in (a,b,c,d)
。
假設所有外鍵都有適當的約束,是否有一個簡單的SQL語句來刪除在數據庫中任何地方沒有引用的行?SQL刪除孤兒
像delete from the_table
那樣簡單,只需跳過任何帶有子記錄的行?
我試圖避免手動循環表或添加類似where the_SK not in (a,b,c,d)
。
您可能能夠使用擴展DELETE
聲明在10g中包含錯誤日誌。
首先使用DBMS_ERRLOG
創建一個記錄表(這僅僅是一個帶有一些額外的前綴列原始表的副本:ORA_ERR_MESG$, ..., ORA_ERR_TAG$
)現在
execute dbms_errlog.create_error_log('parent', 'parent_errlog');
,你可以使用delete語句的錯誤日誌條款捕捉那些現有的完整性約束的所有行:
delete from parent
log errors into parent_errlog ('holding-breath')
reject limit unlimited;
在這種情況下,「持有呼氣」的評論將進入ORA_ERR_TAG$
列。
您可以閱讀完整的文檔here。
如果父表非常龐大,而您只希望刪除一些流浪行,那麼您最終將得到一個parent_errlog
表,它基本上與您的parent
表重複。如果這也不行,你必須做的很長的路要走:
號很明顯,你可以這樣做(但我知道你寧願不):
delete parent
where not exists (select null from child1 where child1.parent_id = parent.parent_id)
and not exists (select null from child2 where child2.parent_id = parent.parent_id)
...
and not exists (select null from childn where childn.parent_id = parent.parent_id);
最簡單的方法可能是編寫一個應用程序或存儲過程,該應用程序或存儲過程試圖一次一個地刪除表中的行,並簡單地忽略由於外鍵約束而導致的故障。之後,所有不在外鍵約束下的行都應該被刪除。根據所需/可能的性能,這可能是一個選項。要做到這一點
一種方式是寫像下面這樣:
eForeign_key_violation EXCEPTION;
PRAGMA EXCEPTION_INIT(eForeign_key_violation, -2292);
FOR aRow IN (SELECT primary_key_field FROM A_TABLE) LOOP
BEGIN
DELETE FROM A_TABLE A
WHERE A.PRIMARY_KEY_FIELD = aRow.PRIMARY_KEY_FIELD;
EXCEPTION
WHEN eForeign_key_violation THEN
NULL; -- ignore the error
END;
END LOOP;
如果一個孩子行存在的DELETE將失敗,沒有行會被刪除,你可以繼續你的下一個重點。
請注意,如果您的表格很大,則可能需要很長時間。
不錯,我不知道這個錯誤記錄。這樣我既不需要指定孩子也不需要遍歷行,但我認爲你應該添加「拒絕限制無限」(或任何數字)。事實上,刪除仍然失敗。 – RichN 2010-01-12 07:56:19
斑點 - 添加到我的答案 – 2010-01-12 13:53:45