批可以有多個Bills可以有多個BillLines。我已在他們之間刪除CASCADE FK,這樣如果刪除批處理,則相關的Bill和BillLine記錄也會被刪除。如果您刪除了賬單,則關聯的BillLines將被刪除,但批次記錄不受影響。現在,如果某個數據條件與一個或多個關聯的BillLine記錄存在關聯,則需要防止刪除該Bill。INSTEAD OF DELETE與ON DELETE CASCADE FK的觸發衝突
表比爾顯然需要INSTEAD OF DELETE觸發器。 BillLine.BillId具有引用Bill.BillId的ON DELETE CASCADE FK。這很有意義,因爲INSTEAD OF DELETE觸發器有效地替代了CASCADE功能,所以我需要將該FK設置爲ON DELETE NO ACTION。當我刪除賬單時,INSTEAD OF DELETE將根據特定的數據條件刪除相關的BillLine記錄或引發異常。到現在爲止還挺好。
但是,因爲Bill.BatchId具有引用Batch.BatchId的ON DELETE CASCADE FK,所以SQL Server不會讓我創建觸發器。這我不明白。爲什麼我需要在Batch上創建一個INSTEAD OF DELETE觸發器,僅僅是因爲我有一個針對Bill的?
下面創建表和鍵的代碼(省略了所有無關的列和鍵)是現在的情況,沒有ON DELETE CASCADE子句。問題是,爲什麼FK_Bill_Batch_BatchId不能擁有該子句,而不必創建額外的INSTEAD OF DELETE觸發器?
CREATE TABLE [Batch](
[BatchId] [bigint] NOT NULL,
CONSTRAINT [PK_Batch_BatchId] PRIMARY KEY CLUSTERED
(
[BatchId] ASC
)
)
CREATE TABLE [Bill](
[BillId] [bigint] NOT NULL,
[BatchId] [bigint] NOT NULL,
[ReversesBillId] [bigint] NULL,
CONSTRAINT [PK_Bill_BillId] PRIMARY KEY CLUSTERED
(
[BillId] ASC
)
)
ALTER TABLE [Bill] WITH CHECK ADD CONSTRAINT [FK_Bill_Batch_BatchId] FOREIGN KEY([BatchId])
REFERENCES [Batch] ([BatchId])
ALTER TABLE [Bill] WITH NOCHECK ADD CONSTRAINT [FK_Bill_ReversesBillId] FOREIGN KEY([ReversesBillId])
REFERENCES [Bill] ([BillId])
CREATE TABLE [BillLine](
[BillLineId] [bigint] NOT NULL,
[BillId] [bigint] NOT NULL,
[ReversedByBillLineId] [bigint] NULL,
CONSTRAINT [PK_BillLine_BillLineId] PRIMARY KEY CLUSTERED
(
[BillLineId] ASC
)
)
ALTER TABLE [BillLine] WITH CHECK ADD CONSTRAINT [FK_BillLine_Bill_BillId] FOREIGN KEY([BillId])
REFERENCES [Bill] ([BillId])
ALTER TABLE [BillLine] WITH CHECK ADD CONSTRAINT [FK_BillLine_ReversedByBillLineId] FOREIGN KEY([ReversedByBillLineId])
REFERENCES [BillLine] ([BillLineId])
GO
CREATE TRIGGER [Bill_Delete]
ON [Bill]
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON
DECLARE @BillId UNIQUEIDENTIFIER
DECLARE myCursor CURSOR LOCAL FORWARD_ONLY
FOR SELECT b.[BillId]
FROM deleted b
JOIN [Batch] bt on b.[BatchId] = bt.[BatchId]
OPEN myCursor
FETCH NEXT FROM myCursor INTO @BillId
WHILE @@FETCH_STATUS = 0
BEGIN
-- Delete BillLine records reversed by another BillLine in the same Bill
DELETE FROM [BillLine]
WHERE [BillId] = @BillId
AND [ReversedByBillLineId] IN
(SELECT bl.[BillLineId]
FROM [BillLine] bl
WHERE bl.BillId = @BillId
);
-- Delete all remaining BillLine records for the Bill
-- If the BillLine is reversed by a BillLine in a different Bill, the FK will raise an exception.
-- That is the desired behavior.
DELETE FROM [BillLine]
WHERE [BillId] = @BillId;
-- Delete the Bill
DELETE FROM [Bill]
WHERE [BillId] = @BillId;
FETCH NEXT FROM myCursor INTO @BillId
END
END
GO
CREATE TRIGGER [Batch_Delete]
ON [Batch]
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON
DECLARE @BatchId UNIQUEIDENTIFIER
DECLARE myCursor CURSOR LOCAL FORWARD_ONLY
FOR SELECT [BatchId]
FROM deleted
OPEN myCursor
FETCH NEXT FROM myCursor INTO @BatchId
WHILE @@FETCH_STATUS = 0
BEGIN
-- Delete all Bill records for the Batch.
-- Another INSTEAD OF DELETE trigger on Bill will attempt to delete the associated BillLine records in the correct order.
-- If the BillLine is reversed by a BillLine in a different Bill, FK_BillLine_ReversedByBillLineId will raise an exception.
-- That is the desired behavior.
DELETE FROM [Bill]
WHERE [BatchId] = @BatchId;
FETCH NEXT FROM myCursor INTO @BatchId
END
END
如果你嘗試更換Batch_Delete觸發與ON DELETE CASCADE: DROP TRIGGER [Batch_Delete] ALTER TABLE [草案] DROP CONSTRAINT [FK_Bill_Batch_BatchId] ALTER TABLE [Bill] WITH CHECK ADD CONSTRAINT [FK_Bill_Batch_BatchId] FOREIGN KEY([BatchId]) REFERENCES [Batch]([BatchId])ON DELETE CASCADE;
你會得到這樣的:
Msg 1787, Level 16, State 0, Line 2
Cannot define foreign key constraint 'FK_Bill_Batch_BatchId' with cascaded DELETE or UPDATE on table 'Bill' because the table has an INSTEAD OF DELETE or UPDATE TRIGGER defined on it.
Msg 1750, Level 16, State 0, Line 2
Could not create constraint. See previous errors.
我不明白爲什麼一個在這個方向DELETE CASCADE應該有什麼關係條例草案表中的INSTEAD OF DELETE觸發器。
你可以發佈你的create table語句嗎?據我所知,SQL Server不允許爲子表創建'INSTEAD OF'觸發器,而不是爲父項創建。 – a1ex07
我加了代碼。你可以創建一個新的數據庫並運行它來創建表,鍵和觸發器。無需添加任何數據。 –
這是您的問題,但不要在觸發器中使用cusror,如果一大組記錄被刪除,這可能會造成巨大的性能問題。 – HLGEM