2012-12-19 82 views
1

我有一個巨大的遺留數據庫,其中有一個表的多個外鍵指向另一個表,並且沒有看到單個級聯,類似於下面的示例表:如何在沒有ON DELETE CASCADE的情況下刪除(衝突參考約束)

create table Users (
    Id int primary key identity, 
    Name varchar(max) 
) 

create table Products (
    Id int primary key identity, 
    Name varchar(max), 
    CreatedBy int foreign key references Users(Id), 
    UpdatedBy int foreign key references Users(Id) 
) 

insert into Users values('Bar') 
insert into Users values('Baz') 
insert into Products values('Foo', 1, 2) 

我需要能夠刪除一些舊的數據,但它當然拋出引用異常:

delete from Users where Name='Bar' 

DELETE語句衝突與基準約束「FK__Products__Create__ 1AD3FDA4" 。數據庫「Foo」中出現衝突,表「dbo.Products」,列'CreatedBy'。


由於我不能predelete所有引用的數據庫的極度複雜性,所以我想添加臨時外鍵編程設置,以解決他們的級聯。然而,對於有多個外鍵另一個表這個特殊的表,這導致cycles or multiple cascade paths第二UpdatedBy改變:

alter table Products add foreign key (CreatedBy) references Users(Id) on delete cascade 
alter table Products add foreign key (UpdatedBy) references Users(Id) on delete cascade 

表「產品」可能會導致循環引進國外KEY約束「FK__Products__Update__1DB06A4F」或多個級聯路徑。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY約束。


我怎樣才能讓delete from Users where工作,同時保持參照完整性,或者通過某種方式讓周圍的多個級聯路徑問題或以其他方式?

+0

請考慮以下事項:要刪除ID = 3的用戶。有一個產品是由該用戶創建的,並且由用戶使用'ID = 5'進行更新。假設在刪除用戶'3'時,您將刪除該產品作爲級聯的一部分,那麼您需要查詢由'ID = 5'更新的所有產品。你會錯過一種產品!或者,您可以保留產品並將'createdBy'設置爲'NULL',這樣您就不會錯過重要信息。但這當然不是級聯刪除。你需要問自己,如果你真的想刪除那個用戶,並且沒有更好的選擇。 –

回答

1

我個人不會這樣做(我會預先刪除所有引用的數據並手動檢查完整性)。請參閱:Can foreign key constraints be temporarily disabled using T-SQL?

報價:

-- disable all constraints 
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all" 

刪除你的數據,一旦限制被禁止,但要記得把他們重新打開之後!

-- enable all constraints 
EXEC sp_msforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all" 

另請注意,存儲過程sp_msforeachtable未被記錄,並可能在未來的SQL Server發行版中消失。

如果您不想全面禁用約束條件(也許您有適用的表的列表),則只需將其禁用即可,如上面的代碼中所示。

ALTER TABLE [Products] NOCHECK CONSTRAINT ALL 
DELETE FROM [Users] where Name='Bar' 
ALTER TABLE [Products] WITH CHECK CHECK CONSTRAINT ALL 

所有功勞都歸功於kristof's answer。請投票!

+0

謝謝,正如OP中提到的,預先引用並不是一個真正的選項,db是絕對巨大的,並且它不是生產功能來將意義資源投入到數百個表中。我不想禁用所有的約束檢查,因爲我希望所有與刪除的用戶相關的垃圾也被刪除,而不是無處不在。 –

+0

有人真的只是necro-downvote這個答案?! – Codesleuth