計劃:使用INSTEAD OF INSERT
觸發器將失敗的插入重定向到「掛起」表。這些行保留在「待處理」表中,直到某些附加信息被插入另一個表中;當這個新的信息可用時,掛起的行被移動到它們的原始目的地。INSTEAD OF UPDATE的INSERTED表爲什麼爲空?
背景:交易記錄與持倉相關。更新交易的服務可以具有尚未存在於數據庫中的信息,例如尚未被插入的持有人的交易(請不要關注該系統的那部分「爲什麼」,我可以'改變這一點)。
問題:該INSTEAD OF INSERT
觸發器工作,但我與INSTEAD OF UPDATE
觸發器有問題。當應用UPDATE
,但要更新的行位於「待處理」表中時,觸發器中的INSERTED
表爲空,因此我無法更新「待處理」表。這裏是(簡化)DDL:
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
扳機,做UPDATE
作品當Trade
表中存在該行,但不是在該行不存在,INSERTED
虛表是空的。我在觸發器中添加了一些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應用到表之前應執行。
任何人都可以解釋爲什麼INSERTED
表是空的?我敢肯定,解決方案將是一件小事,但我似乎無法得到它的工作。
我加入到貿易或TradePending表取決於IF EXISTS檢查的結果,因爲我的理解是你必須加入到INSERTED表才能訪問它(或者我錯誤地認爲?)要測試你的理論我把「選擇計數(*)從插入」,計數= 0.打印同樣從刪除,計數= 0. – Tony 2010-12-02 14:29:31
好吧,我錯了需要加入到INSERTED訪問它。我改變了更新到TradePending表是:「UPDATE TradePending \t SET BuySell =(SELECT BuySell FROM插入 \t \t WHERE inserted.HoldingID = TradePending.HoldingID) 和解析器很樂意這麼做,但它運行的時候,我得到錯誤:「無法將NULL值插入'BuySell'列' – Tony 2010-12-02 14:36:04