プラン:INSTEAD OF INSERT
トリガーを使用して、失敗した挿入を「保留」テーブルにリダイレクトします。これらの行は、いくつかの追加情報が別のテーブルに挿入されるまで「保留中」テーブルに残ります。この新しい情報が利用可能になると、保留中の行は元の宛先に移動されます。INSTEAD OF UPDATEトリガのINSERTEDテーブルが空であるのはなぜですか?
背景:ホールディングに関連する取引が記録されます。トレードを更新するサービスは、まだ挿入されていないホールディングの取引(システムのその部分の「なぜ」に焦点を当ててはいけない、それを変更する)。
問題:トリガーは動作しますが、私はINSTEAD OF UPDATE
トリガーで問題があります。 UPDATE
が適用されているが、更新される行が '保留中'のテーブルにある場合、INSERTED
テーブルがトリガー内に空であるため、 '保留中'テーブルを更新できません。
CREATE TABLE [Holding] (
[HoldingID] INTEGER NOT NULL,
[InstrumentID] INTEGER,
CONSTRAINT [PK_Holding] PRIMARY KEY ([HoldingID])
)
GO
CREATE TABLE [Trade] (
[TradeID] INTEGER IDENTITY(1,1) NOT NULL,
[HoldingID] INTEGER NOT NULL,
[BuySell] CHAR(1) NOT NULL,
CONSTRAINT [PK_TradeSummary] PRIMARY KEY ([TradeID])
)
GO
ALTER TABLE [Trade] ADD CONSTRAINT [CC_Trade_BuySell]
CHECK (BuySell = 'B' or BuySell = 'S')
GO
ALTER TABLE [Trade] ADD CONSTRAINT [Holding_Trade]
FOREIGN KEY ([HoldingID]) REFERENCES [Holding] ([HoldingID])
GO
CREATE TABLE [TradePending] (
[TradeID] INTEGER IDENTITY(1,1) NOT NULL,
[HoldingID] INTEGER NOT NULL,
[BuySell] CHAR(1) NOT NULL,
CONSTRAINT [PK_TradePending] PRIMARY KEY ([TradeID])
)
GO
ALTER TABLE [TradePending] ADD CONSTRAINT [CC_TradePending_BuySell]
CHECK (BuySell = 'B' or BuySell = 'S')
GO
-- The INSERT trigger works, when the referenced holding does not exist the row is redirected to the TradePending table.
CREATE TRIGGER [Trg_Trade_Insert]
ON [Trade]
INSTEAD OF INSERT
AS
IF NOT EXISTS (SELECT 1
FROM inserted i INNER JOIN Holding h
ON i.HoldingID = h.HoldingID)
BEGIN
INSERT TradePending(HoldingID, BuySell) SELECT HoldingID, BuySell FROM inserted
END
ELSE
BEGIN
INSERT Trade(HoldingID, BuySell) SELECT HoldingID, BuySell FROM inserted
END
GO
トリガ行は行が存在しない場合、INSERTED
仮想テーブルが空であるTrade
テーブル内に存在するがないUPDATE
作品を行うには:ここでは(簡体字)DDLです。トリガーにPRINT
文を追加して、何が起きているのかを確認しようとしました。ここ
CREATE TRIGGER [dbo].[Trg_Trade_Update]
ON [dbo].[Trade]
INSTEAD OF UPDATE
AS
DECLARE @s char(1)
DECLARE @h int
IF NOT EXISTS (SELECT 1
FROM inserted i INNER JOIN Trade t
ON i.HoldingID = t.HoldingID)
BEGIN
PRINT 'Update TradePending'
SET @h = COALESCE((SELECT i.HoldingID
FROM TradeSummaryPending t INNER JOIN inserted i
ON t.HoldingID = i.HoldingID), 0)
SET @a = COALESCE((SELECT i.BuySell
FROM TradeSummaryPending t INNER JOIN inserted i
ON t.HoldingID = i.HoldingID), 'N')
PRINT 'h=' + CAST(@h AS varchar(1)) + ' s=' + @s
UPDATE TradePending
SET BuySell = i.BuySell
FROM Trade t INNER JOIN inserted i
ON t.HoldingID = i.HoldingID
END
ELSE
BEGIN
PRINT 'Update Trade'
SET @h = (SELECT i.HoldingID
FROM Trade t INNER JOIN inserted i
ON t.HoldingID = i.HoldingID)
SET @s = (SELECT i.BuySell
FROM Trade t INNER JOIN inserted i
ON t.HoldingID = i.HoldingID)
PRINT 'h=' + CAST(@h AS varchar(1)) + ' s=' + @s
UPDATE Trade
SET BuySell = i.BuySell
FROM Trade t INNER JOIN inserted i
ON t.HoldingID = i.HoldingID
END
は、テストのためのいくつかのサンプルデータです:更新を実行するから
-- Create a Holding and a Trade, this will be inserted as normal.
INSERT Holding VALUES(1,100)
INSERT TradeSummary VALUES(1,'B')
-- Create a Trade where the Holding does not exists,
-- row redirected to TradePending table.
INSERT TradeSummary values(2,'S')
-- Update the first trade to be a Buy, updates the `Trade` table
UPDATE Trade SET BuySell = 'S' WHERE HoldingID = 1
出力:
Update Trade
h=1 s=S
(1 row(s) affected)
(1 row(s) affected)
今のみTradePendingテーブルに存在する行更新:
をUPDATE Trade SET BuySell = 'B' WHERE HoldingID = 2
Update TradePending
h=0 s=N
(0 row(s) affected)
(0 row(s) affected)
INSERTED
表は、これがINSTEAD OF
トリガーで、SQLがテーブルに適用される前に実行する必要があるにもかかわらず、今の行を含むように表示されます。次の出力になり3210。
INSERTED
テーブルが空である理由を説明できる人はいますか?私は解決策が何か自明なものになると確信していますが、私はそれを働かせるようには見えません。
分析していただきありがとうございます。質問されていなかった質問に「これは奇妙なアイデアですか?」と思われます。 "あなたはTradePendingにある行のUPDATE文を発行します。 "アプリケーションからTradePendingテーブルを隠そうとしていました。私はUPDATE文を傍受して、TradePendingテーブルに変更を適用できると思っていました。(たぶん間違っているでしょう) – Tony
ありがとうあなたの助けのための利益、そして更新された答え。保留中の取引を更新する方法がない場合は、解決策を再考する必要があります。私は、データベースへのサービス書き込みに大きな変更を加えることを避けようとしていました。 – Tony