计划:使用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