最后的编辑更新 - 解决 - 解决方案下面从SQL Server表变量
我不能相信,我不知道这一点,但显然的问题是,该表变量和真表都有同样的名字:@CHECKERS和dbo.CHECKERS。触发器显然使两者混淆。我通过改变触发器中插入和更新操作的顺序来发现这一点,以便在从表变量更新后插入到真实表中。突然之间,更新开始没有问题。
当然,我只创建了dbo.CHECKERS来调试@CHECKERS,所以很明显存在一些原来存在的问题,但无论如何,问题已经解决,触发器工作得很好。我在下面发布它,如果您愿意,随时提供任何反馈。我不是专家(很清楚),并且总是乐于接受建设性的反馈。
感谢大家的帮助和评论。我希望这篇文章可以帮助别人那里避免头痛...
查询 - 解决方案
ALTER TRIGGER CatchChange ON [dbo].[Orders]
-- Last Updated : 07 Oct 2014
AFTER UPDATE
NOT FOR REPLICATION
-- Trigger not fired by agent updates
AS
BEGIN
IF UPDATE(UpdateRecordDate)
-- Trigger fired only by user updates that include a timestamp.
-- Does **NOT** fire from primary stored procedure (dictated by UpdateRecordDate).
BEGIN
-- Table variable for storing **multi-row updates**
-- Using scalar variables will not work! Look it up.
DECLARE @CHECKERS AS TABLE
( OrderNum INT,
Old_DCB INT,
New_DCB INT,
Old_MC INT,
New_MC INT,
Old_P2 NUMERIC(28,3),
New_P2 NUMERIC(28,3),
Old_PQ NUMERIC(28,3),
New_PQ NUMERIC(28,3),
Old_QT NUMERIC(28,3),
New_QT NUMERIC(28,3)
)
-- Old & new values populated to table variable.
-- We can add a table in the same format as the variable &
-- then check what values were passed, if necessary.
-- The INSERT for this scenario is commented out at the end.
INSERT INTO @CHECKERS
SELECT I.OrderNo,
D.DriverCB,
I.DriverCB,
D.MCode,
I.MCode,
D.Price2,
I.Price2,
D.PriceQuantity2,
I.PriceQuantity2,
D.Quantity1,
I.Quantity1
FROM Inserted I
JOIN Deleted D ON I.Orderno = D.OrderNo
-- These checks are crucial, as they cut down on reiteration.
-- Without them, the program would fire the trigger redundantly.
-- Here we check for changes to the relevant values &
-- ensure that the update was a new one, not a repetitive one.
WHERE I.OrderKind = 0
AND isnull(D.UpdateRecordDate,convert(DATETIME,0)) <> isnull(I.UpdateRecordDate,convert(DATETIME,0))
AND (D.DriverCB <> I.DriverCB
OR D.MCode <> I.MCode
OR D.Price2 <> I.Price2
OR D.PriceQuantity2 <> I.PriceQuantity2
OR D.Price3 <> I.Price3
OR D.PriceQuantity3 <> I.PriceQuantity3
OR D.Quantity1 <> I.Quantity1)
-- Case conditions are preferable in this instance to IF conditions.
-- All relevant values are checked here against dictating conditions &
-- updated accordingly.
UPDATE O
SET
O.DriverCB = CASE
WHEN C.New_DCB = 0
THEN NULL
ELSE O.DriverCB
END,
<...>,
O.Quantity4 = CASE
WHEN C.New_QT > 0
THEN O.Quantity1
ELSE O.Quantity4
END
FROM Orders O
INNER JOIN @CHECKERS C ON O.OrderNo = C.OrderNum
-- This is the INSERT which populates the debug table, if you want.
-- Naturally, the name here must match the name of the created table!
-- And yes, DD, you need to create the ACTUAL TABLE outside of this trigger. :)
/* INSERT INTO CheckMe
SELECT C.ID,
C.OrderNum,
C.Old_DriverCodeBizua,
C.New_DriverCodeBizua,
C.Old_MaslulCode1,
C.New_MaslulCode1,
C.Old_Price2,
C.New_Price2,
C.Old_PriceQuntity2,
C.New_PriceQuntity2,
C.Old_Quntity,
C.New_Quntity
FROM @CHECKERS C */
END
END
GO
结束问题 - 解决方案
--------开始原创帖子--------
我有一位客户,他需要我修饰一堆旧的触发器pe改变各种功能。一般来说,我不赞成这一点,并认为他们的计划应该更新 - 但无论如何。
存在三个触发器,我只需要将它们组合成一个单一的触发器,它可以更平滑地工作,并且有更多的条件。 (目前,完全缺乏条件使得在每一个操作运行的触发,这是观赏痛苦的缓慢。)
总之,我已经创建了我声明表变量(以下查询)一个新的触发。我这样做是为了直接控制列名,而不是简单地使用SELECT X INTO #temp。此后,我试图使用CASE检查来更新主表中的各个字段,这取决于我的表变量中记录的更改。
问题是更新没有做任何事情。我没有得到任何错误,但主表中的值保持不变。为了确保表变量获取值并且可以使用,我向测试数据库添加了一个新表,并且在触发器的每次触发时,我将当前包含在表变量中的值插入到新表中,如下所示:
DECLARE @CHECKERS AS TABLE
( OrderNum INT,
Old_DCB INT,
New_DCB INT,
Old_MC INT,
New_MC INT,
Old_QT NUMERIC(28,3),
New_QT NUMERIC(28,3)
)
INSERT INTO @CHECKERS
SELECT I.OrderNo,
D.DriverCB,
I.DriverCB,
D.MCode,
I.MCode,
D.Quantity,
I.Quantity
FROM Inserted I
JOIN Deleted D ON I.OrderNo = D.OrderNo
WHERE I.OrderKind = 0
AND (D.DriverCB <> I.DriverCB
OR D.MCode1 <> I.MCode1
OR D.Quantity <> I.Quantity)
INSERT INTO CHECKERS
SELECT OrderNum,
Old_DCB,
New_DCB,
Old_MC,
New_MC,
Old_QT,
New_QT
FROM @CHECKERS
-- An actual table created to check functionality
-- Works up until this point
UPDATE Orders
SET Quantity2 = CASE
WHEN New_QT > 0 THEN New_QT
ELSE Quantity2
END
FROM @CHECKERS C
WHERE OrderNo = C.OrderNum
当然,也有实际触发更多的更新,但你的想法。
任何想法为什么更新订单没有通过?可能是小小的,愚蠢的,尴尬的 - 但我再说一遍,);谢谢。
--------结束的原贴--------
- 编辑:
我也曾尝试写入更新为这样:
UPDATE O
SET Quantity2 = CASE
WHEN C.New_QT > 0 THEN C.New_QT
ELSE Quantity2
END
FROM @CHECKERS C
INNER JOIN Orders O on O.OrderNo = C.OrderNum
这种方法给出了相同的结果:没有错误消息(或任何其他消息,对于这个问题),并没有更新......
- 2第二编辑:
如果我用实际的表跳棋,而不是表变量@CHECKERS,更新通行证:
UPDATE O
SET Quantity2 = CASE
WHEN C.New_QT > 0 THEN C.New_QT
ELSE Quantity2
END
FROM CHECKERS C -- Actual table, not a table variable!
INNER JOIN Orders O on O.OrderNo = C.OrderNum
这也是在JOIN工程订单的存在,不管:
UPDATE Orders
SET Quantity2 = CASE
WHEN C.New_QT > 0 THEN C.New_QT
ELSE Quantity2
END
FROM CHECKERS C -- Actual table, not a table variable!
WHERE OrderNo = C.OrderNum
现在唯一的问题是,在客户的数据库中,我不能添加真正的表CHECKERS。我将它添加到我的测试数据库中,只是为了澄清这些值是否传入表变量!这是我不熟悉的表变量的限制吗?我很难在联机文档中发现任何此类限制...
如果您选择而不是更新查询,您是否看到应该更新的行? – 2014-10-06 10:02:15
你在'UPDATE'语句后看到什么信息?也许'更新0'?或者也许有些不同? – 2014-10-06 10:12:14
@DanBracuk是的,如果我切换到select语句,我会看到要更新的行。 – 2014-10-06 10:16:07