Cal*_*vin 5 t-sql sql-server sql-server-2005
好.我正在对表中的单行进行更新.除主键外,所有字段都将被新数据覆盖.但是,并非所有值都会更改更新的b/c.例如,如果我的表格如下:
TABLE (id int ident, foo varchar(50), bar varchar(50))
Run Code Online (Sandbox Code Playgroud)
初始值是:
id foo bar
-----------------
1 hi there
Run Code Online (Sandbox Code Playgroud)
然后我执行 UPDATE tbl SET foo = 'hi', bar = 'something else' WHERE id = 1
我想知道的是哪个列的值已更改,其原始值是什么以及它的新值是什么.
在上面的例子中,我希望看到列"bar"从"there"更改为"something else".
可以不进行逐列比较吗?是否有一些优雅的SQL语句,如EXCEPT,将比行更细粒度?
谢谢.
没有可以运行的特殊语句可以准确地告诉您哪些列已更改,但是查询并不难写:
DECLARE @Updates TABLE
(
OldFoo varchar(50),
NewFoo varchar(50),
OldBar varchar(50),
NewBar varchar(50)
)
UPDATE FooBars
SET <some_columns> = <some_values>
OUTPUT deleted.foo, inserted.foo, deleted.bar, inserted.bar INTO @Updates
WHERE <some_conditions>
SELECT *
FROM @Updates
WHERE OldFoo != NewFoo
OR OldBar != NewBar
Run Code Online (Sandbox Code Playgroud)
如果您尝试通过这些更改实际执行某些操作,那么最好编写一个触发器:
CREATE TRIGGER tr_FooBars_Update
ON FooBars
FOR UPDATE AS
BEGIN
IF UPDATE(foo) OR UPDATE(bar)
INSERT FooBarChanges (OldFoo, NewFoo, OldBar, NewBar)
SELECT d.foo, i.foo, d.bar, i.bar
FROM inserted i
INNER JOIN deleted d
ON i.id = d.id
WHERE d.foo <> i.foo
OR d.bar <> i.bar
END
Run Code Online (Sandbox Code Playgroud)
(当然你可能想在触发器中做更多的事情,但是有一个非常简单的动作的例子)
您可以使用COLUMNS_UPDATED而不是UPDATE但我觉得它很痛苦,它仍然不会告诉您哪些列实际更改了,只是哪些列包含在UPDATE语句中.因此,例如,您可以编写UPDATE MyTable SET Col1 = Col1,它仍会告诉您Col1已更新,即使实际上没有一个值更改.在编写触发器时,您需要实际测试单个前后值,以确保您获得真正的更改(如果这是您想要的).
PS你也可以UNPIVOT像Rob说的那样,但是你仍然需要在UNPIVOT子句中明确指定列,这不是魔术.
| 归档时间: |
|
| 查看次数: |
11892 次 |
| 最近记录: |