【发布时间】:2010-12-02 11:50:36
【问题描述】:
计划:使用INSTEAD OF INSERT 触发器将失败的插入重定向到“待处理”表。这些行保留在“待处理”表中,直到在另一个表中插入一些附加信息;当此新信息可用时,待处理的行将移至其原始目的地。
背景:交易记录与控股有关。更新交易的服务可以有尚未在数据库中的信息,例如尚未插入的持仓交易(请不要专注于系统那部分的“为什么”,我可以)不要改变它)。
问题: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 表是空的?我确信解决方案将是微不足道的,但我似乎无法让它发挥作用。
【问题讨论】:
标签: sql sql-server sql-server-2008 triggers