複数のBillLinesを持つことができる複数のBillsを持つことができます。バッチを削除すると、関連するBillとBillLineのレコードも削除されるように、それらの間にON DELETE CASCADE FKがあります。請求書を削除すると、関連するBillLinesは削除されますが、バッチレコードは影響を受けません。これで、関連するBillLineレコードが1つ以上ある特定のデータ条件がある場合、Billの削除を防止する必要があります。削除の代わりにON DELETE CASCADE FKとのトリガーの競合
テーブルビルドには、INSTEAD OF DELETEトリガーが必要です。 BillLine.BillIdには、Bill.BillIdを参照するON DELETE CASCADE FKがあります。なぜなら、INSTEAD OF DELETEトリガーがCASCADEの機能を効果的に置き換えるため、FKが代わりにNO DELETE NO ACTIONを行う必要があるということです。請求書を削除すると、削除の代わりに関連付けられたBillLineレコードが削除されるか、特定のデータ条件に応じて例外が発生します。ここまでは順調ですね。
しかし、Bill.BatchIdにはBatch.BatchIdを参照するON DELETE CASCADE FKがあるため、SQL Serverはトリガーを作成させません。これは私が理解していない。なぜ私はBillに1つしかないので、バッチでINSTEAD OF DELETEトリガーを構築する必要がありますか?
以下の表とキーを作成するコード(無関係な列とキーはすべて省略)は、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
あなたはCASCADE、ON DELETEでBatch_Deleteトリガーを交換しようとした場合:[FK_Bill_Batch_BatchId] DROP TRIGGER [Batch_Delete] ALTER TABLE [ビル] DROP制約を。 [バッチ]([BatchId])ON DELETE CASCADE; [BUCH] [BUCH]
あなたはこれを取得します:ONビル・テーブルにINSTEAD OF DELETEトリガーとは何かを持っている必要があり、この方向に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.
。
create table statementsを転記できますか?私が知っていることから、SQL Serverでは、親テーブルではなく、子テーブルに対して「INSTEAD OF」トリガーを作成させることはできません。 – a1ex07
私はコードを追加しました。新しいデータベースを作成して実行するだけで、テーブル、キー、トリガーを作成できます。データを追加する必要はありません。 –
これはあなたの質問とは別のものですが、トリガーでcusrorを使用しないでください。大きなグループのレコードが削除されると、大きなパフォーマンス上の問題が発生する可能性があります。 – HLGEM