能,但必须用inserted和deleted伪表配合;output不计算差异,只返回更新前后完整行,需自行逐字段比对(注意null比较),且目标表不能与源表同名、同schema或含触发器。

OUTPUT子句能直接拿到UPDATE前后的值吗?
能,但必须用 INSERTED 和 DELETED 两个伪表配合。SQL Server 不提供类似「diff()」的内置函数,OUTPUT 本身不计算差异,只暴露变更前后的行数据——你需要自己比对字段。
常见误区是以为 OUTPUT 能直接输出「变化了哪些列」或「旧值→新值」的映射;实际它只返回两套完整行,得靠后续逻辑(比如在临时表里做字段级比较)才能得出差异。
怎么写一个带差异记录的UPDATE语句?
核心结构是:UPDATE ... SET ... OUTPUT DELETED.*, INSERTED.* INTO @temp_table。关键点在于:必须显式指定字段名(避免 * 在列顺序/数量不一致时出错),且目标表不能有触发器(否则 OUTPUT 被禁用)。
-
DELETED包含更新前的整行,INSERTED是更新后的整行,二者主键值相同 - 若只想记录变动字段,建议先将
OUTPUT结果插入临时表,再用CASE WHEN DELETED.col1 INSERTED.col1 THEN 'col1' END逐字段判断 - 注意
NULL比较:要用IS NULL判断,不能直接用=或 - 如果 UPDATE 涉及多行,
OUTPUT返回结果集无序,别依赖返回顺序
为什么OUTPUT写入永久表会失败?
因为 OUTPUT INTO 目标表不能是被 UPDATE 的同一张表,也不能是视图、远程表或有启用 CDC 的表。最常踩的坑是误把日志表建在同一个数据库下却忘了加 schema 限定,导致 SQL Server 误判为「目标表与源表同构」而报错 Msg 334, Level 16。
安全做法是:用 OUTPUT INTO @table_variable 先暂存,再批量插入日志表;或者确保日志表明确使用不同 schema(如 audit.LogTable),且该表没有触发器或 FOREIGN KEY 约束指向源表。
性能和事务一致性要注意什么?
OUTPUT 是原子操作的一部分,它和 UPDATE 在同一事务内完成,不会丢失中间状态。但副作用明显:每多输出一个字段,就多一份内存拷贝;若输出大量行+宽表,可能引发 tempdb 压力或阻塞。
- 避免在高并发 UPDATE 场景中输出全部字段,只选业务真正需要审计的列
- 不要在
OUTPUT中调用函数(如GETDATE()或自定义函数),它们可能被多次求值 - 如果需记录操作人、时间等上下文,应在 UPDATE 外层用变量赋值后一并输出,例如
OUTPUT ..., @operator, GETDATE()
真正麻烦的是跨库或跨实例场景——OUTPUT INTO 不支持链接服务器,这种时候只能退回到触发器 + 服务端日志的方案。











