SQL Server如何为全库创建触发器实现updated_at字段自动更新?
方案1:动态SQL批量生成同规则触发器
适合不想改业务代码、纯数据库层面解决的场景,就算上百张表也能几秒批量处理完成,代码如下:
DECLARE @TableName NVARCHAR(128) DECLARE @TriggerName NVARCHAR(128) DECLARE @SQL NVARCHAR(MAX) -- 声明游标遍历所有符合条件的用户表 DECLARE table_cursor CURSOR FOR SELECT t.name FROM sys.tables t INNER JOIN sys.columns c1 ON t.object_id = c1.object_id AND c1.name = 'updated_at' INNER JOIN sys.columns c2 ON t.object_id = c2.object_id AND c2.name = 'id' WHERE t.type = 'U' OPEN table_cursor FETCH NEXT FROM table_cursor INTO @TableName WHILE @@FETCH_STATUS = 0 BEGIN SET @TriggerName = 'TR_' + @TableName + '_UpdateTimestamp' -- 先清理已存在的同名触发器 IF EXISTS (SELECT * FROM sys.triggers WHERE name = @TriggerName AND parent_id = OBJECT_ID(@TableName)) BEGIN SET @SQL = 'DROP TRIGGER ' + @TriggerName EXEC sp_executesql @SQL END -- 生成创建触发器的语句 SET @SQL = ' CREATE TRIGGER ' + @TriggerName + ' ON ' + @TableName + ' FOR UPDATE AS BEGIN -- 避免updated_at字段自身更新触发递归 IF UPDATE(updated_at) RETURN UPDATE t SET updated_at = SYSDATETIME() FROM ' + @TableName + ' t INNER JOIN inserted i ON t.id = i.id END ' EXEC sp_executesql @SQL FETCH NEXT FROM table_cursor INTO @TableName END CLOSE table_cursor DEALLOCATE table_cursor
这段代码会自动扫描所有带id主键和updated_at字段的用户表,自动创建更新时间触发器,后续新增表后重新执行一次即可。
方案2:ORM全局拦截(适用于有统一ORM框架的项目)
如果你的项目用了EF Core、MyBatis等ORM框架,可以在数据访问层全局配置更新规则,完全不需要维护数据库触发器。以EF Core为例,重写SaveChanges方法即可:
public override int SaveChanges() { // 筛选所有待更新的实体 var modifiedEntries = ChangeTracker.Entries() .Where(e => e.State == EntityState.Modified); foreach (var entry in modifiedEntries) { // 自动给updated_at字段赋值当前时间 entry.Property("updated_at").CurrentValue = DateTime.Now; } return base.SaveChanges(); }
该方案优势是新增表时只要实体类加了updated_at字段就会自动生效,无需额外配置,适合业务代码统一管控的项目。如果存在直接在数据库执行UPDATE语句、多服务直连数据库的场景,该方案不生效,优先选方案1。
方案3:SQL Server 2022+ 原生支持自动更新字段
如果你使用的是SQL Server 2022及更高版本,无需触发器或代码修改,建表时直接定义字段即可实现和MySQLON UPDATE一致的效果:
CREATE TABLE 表名 ( id INT PRIMARY KEY IDENTITY(1,1), -- 其他业务字段 created_at SMALLDATETIME NOT NULL DEFAULT GETDATE(), updated_at SMALLDATETIME NOT NULL DEFAULT GETDATE() GENERATED ALWAYS AS ROW START ) WITH (SYSTEM_VERSIONING = OFF);
该原生方案性能最优,无额外维护成本。
内容的提问来源于stack exchange,提问作者dokichan
相关产品推荐
相关产品推荐

