在SQL Server中编写触发器时获取OLD值及实现指定脚本的方法
针对你提出的两个SQL Server触发器相关问题,我整理了详细的解决方案,都是实际开发中常用的技巧:
1. 在SQL Server触发器中获取旧值(OLD)的方法
SQL Server里并没有MySQL那样直接的OLD关键字,它是通过**系统临时表deleted**来存储触发器触发前的旧数据的。对应的,inserted表用来存储新数据(相当于MySQL的NEW)。
举个实际的小例子,比如你想在Animal表的更新触发器里,把更新前的记录ID和名称存入日志表:
CREATE TRIGGER trg_Animal_RecordOldValue ON Animal AFTER UPDATE AS BEGIN SET NOCOUNT ON; -- 从deleted表读取旧数据插入日志 INSERT INTO Animal_Log (OldAnimalID, OldAnimalName, UpdateTime) SELECT id, nom, GETDATE() FROM deleted; END GO
需要注意:SQL Server的触发器默认是语句级触发器,deleted和inserted表可能包含多行数据(当你的UPDATE语句一次性修改多条记录时),所以处理逻辑要考虑批量场景,别只按单行来写。
2. 将MySQL风格的更新触发器适配为SQL Server语法
你给出的MySQL触发器是在Animal表更新后,把旧数据同步到Animal_histo历史表。下面是完全适配SQL Server的版本,我会逐一说明改动点:
CREATE TRIGGER after_update_animal ON Animal AFTER UPDATE AS BEGIN -- 关闭计数提示,避免触发器返回额外的行数统计信息 SET NOCOUNT ON; INSERT INTO Animal_histo ( id, sexe, date_naissance, nom, commentaires, espece_id, race_id, mere_id, pere_id, disponible, date_histo, utilisateur_histo, evenement_histo ) SELECT deleted.id, deleted.sexe, deleted.date_naissance, deleted.nom, deleted.commentaires, deleted.espece_id, deleted.race_id, deleted.mere_id, deleted.pere_id, deleted.disponible, GETDATE(), CURRENT_USER(), 'UPDATE' FROM deleted; END GO
关键改动说明:
- 移除DELIMITER:SQL Server不需要自定义分隔符,用
GO来分隔独立的批处理语句即可。 - 调整触发器语法结构:SQL Server的触发器定义格式为
CREATE TRIGGER [触发器名] ON [表名] AFTER UPDATE AS BEGIN ... END,不需要FOR EACH ROW(因为SQL Server触发器默认通过deleted/inserted表处理所有受影响的行)。 - 替换OLD为deleted:如第一个问题所说,SQL Server用
deleted表存储更新前的旧数据,所以所有OLD.xxx都替换为deleted.xxx。 - 替换NOW()为GETDATE():SQL Server中获取当前系统时间用
GETDATE()(如果需要更高精度的时间,可以用SYSDATETIME()),NOW()是MySQL专属的写法。 - 添加SET NOCOUNT ON:这是SQL Server触发器的最佳实践,避免触发器执行时返回额外的行数统计信息,干扰调用方的业务逻辑。
- 用SELECT批量插入:因为
deleted表可能包含多条记录(当UPDATE语句修改多行数据时),用SELECT FROM deleted可以一次性插入所有旧数据,比单行VALUES写法更高效且符合SQL Server的特性。
内容的提问来源于stack exchange,提问作者anas mah
相关产品推荐
相关产品推荐

