有一个包含IDU
(PK)和stat
列的表格。如果stat
的第一位为1,我需要将其设置为0并仅在这种情况下运行一些存储过程,否则我什么都不做。
以下是此
的简单查询DECLARE @s INT
-- get the current value of status before update
SET @s = (SELECT stat FROM myTable
WHERE IDU = 999999999)
-- check it first bit is 1
IF (@s & 1) = 1
BEGIN
-- first bit is 1, set it to 0
UPDATE myTable
SET status = Stat & ~1
WHERE IDU = 999999999
-- first bit is one, in this case we run our SP
EXEC SOME_STORED_PROCEDURE
END
但我不确定这个查询是否是最佳的。我听说过OUTPUT
查询的UPDATE
参数,但我发现了如何获取插值。有没有办法获得插入之前的值?
答案 0 :(得分:2)
是的,OUTPUT
子句允许您在更新之前获取之前的值。您需要查看deleted
和inserted
表。
DELETED
是一个列前缀,用于指定由中删除的值 更新或删除操作。以DELETED为前缀的列反映了 完成UPDATE,DELETE或MERGE语句之前的值。
INSERTED
是一个列前缀,用于指定插入或添加的值 更新操作。以INSERTED为前缀的列反映了该值 在UPDATE,INSERT或MERGE语句完成之后但之前 触发器被执行。
-- Clear the first bit without checking what it was
DECLARE @Results TABLE (OldStat int, NewStat int);
UPDATE myTable
SET Stat = Stat & ~1
WHERE IDU = 999999999
OUTPUT
deleted.Stat AS OldStat
,inserted.Stat AS NewStat
INTO @Results
;
-- Copy data from @Results table into variables for comparison
-- Assumes that IDU is a primary key and @Results can have only one row
DECLARE @OldStat int;
DECLARE @NewStat int;
SELECT @OldStat = OldStat, @NewStat = NewStat
FROM @Results;
IF @OldStat <> @NewStat
BEGIN
EXEC SOME_STORED_PROCEDURE;
END;
答案 1 :(得分:1)
无论最佳情况如何,此查询都不是100%安全的。这是因为在SET @s = ...和UPDATE myTable之间,无法保证stat的值没有被更改。如果此代码多次运行,如果两个案例对同一个IDU执行致命关闭,则可能会搞砸。第一个线程会正常,但第二个线程不会,因为第一个线程会在第二个线程读取之后和更新之前更改统计信息。即使在SERIALIZABLE隔离上,select语句也不会锁定超出自己的执行时间。
为了安全起见,你需要在读取之前锁定记录,为此你需要一个更新声明,甚至假的:
DECLARE @s INT
BEGIN TRANSACTION
UPDATE myTable SET stat = stat WHERE IDU = 999999999 --now you row lock your row, make sure no other thread can move along
-- get the current value of status before update
SET @s = (SELECT stat FROM myTable
WHERE IDU = 999999999)
-- check it first bit is 1
IF (@s & 1) = 1
BEGIN
-- first bit is 1, set it to 0
UPDATE myTable
SET status = Stat & ~1
WHERE IDU = 999999999
-- first bit is one, in this case we run our SP
-- COMMIT TRANSACTION here? depends on what SOME_STORED_PROCEDURE does
EXEC SOME_STORED_PROCEDURE
COMMIT TRANSACTION --i believe here you release the row lock
我不确定你的意思是“有没有办法获得插入前的值”,因为你只更新了唯一的数据,stat,你已经从旧记录中读取过,无论你是否更新
答案 2 :(得分:0)
您可以使用INSTEAD OF UPDATE触发器执行此操作。