SQL Server中无需触发器与默认约束自动更新表日期列方案咨询
嘿,这个需求我刚好之前处理过,不用触发器和默认约束的话,其实可以借助数据库的内置特性或者统一封装操作入口来实现,不同数据库的具体方案略有差异,我给你整理了主流数据库的可行办法:
1. SQL Server 方案
方案A:用计算列处理LastModifiedDateTime
CreatedDateTime需要在插入后固定不变,所以没法用计算列(毕竟计算列会随每次查询刷新),但LastModifiedDateTime可以用非持久化计算列来实时返回当前时间:
ALTER TABLE YourTableName ADD LastModifiedDateTime AS SYSDATETIME();
这个列不会存在磁盘上,每次读取的时候自动计算当前系统时间,刚好符合“更新时自动取当前时间”的需求——不过要注意,它不会被持久化存储,如果需要把时间值固定下来(比如要追溯历史时间),那得用下面的存储过程方案。
方案B:封装存储过程统一管控CRUD
这是最稳妥的通用方案,完全避开触发器和默认约束,通过存储过程来强制设置时间字段:
-- 插入用的存储过程 CREATE PROCEDURE InsertYourTable @OtherColumn1 VARCHAR(50), @OtherColumn2 INT AS BEGIN SET NOCOUNT ON; INSERT INTO YourTableName (CreatedDateTime, LastModifiedDateTime, OtherColumn1, OtherColumn2) VALUES (SYSDATETIME(), SYSDATETIME(), @OtherColumn1, @OtherColumn2); END; -- 更新用的存储过程 CREATE PROCEDURE UpdateYourTable @Id INT, @OtherColumn1 VARCHAR(50), @OtherColumn2 INT AS BEGIN SET NOCOUNT ON; UPDATE YourTableName SET LastModifiedDateTime = SYSDATETIME(), OtherColumn1 = @OtherColumn1, OtherColumn2 = @OtherColumn2 WHERE Id = @Id; END;
之后所有插入、更新操作都调用这两个存储过程,就能保证时间字段自动设置,还能统一管控数据操作的逻辑。
2. PostgreSQL 方案
PostgreSQL的生成列没法直接用CURRENT_TIMESTAMP(因为生成列只能依赖表内的其他字段),所以最靠谱的还是封装函数来处理:
-- 插入数据的函数 CREATE OR REPLACE FUNCTION insert_your_table(p_other_column1 VARCHAR, p_other_column2 INT) RETURNS VOID AS $$ BEGIN INSERT INTO your_table (createddatetime, lastmodifieddatetime, other_column1, other_column2) VALUES (CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, p_other_column1, p_other_column2); END; $$ LANGUAGE plpgsql; -- 更新数据的函数 CREATE OR REPLACE FUNCTION update_your_table(p_id INT, p_other_column1 VARCHAR, p_other_column2 INT) RETURNS VOID AS $$ BEGIN UPDATE your_table SET lastmodifieddatetime = CURRENT_TIMESTAMP, other_column1 = p_other_column1, other_column2 = p_other_column2 WHERE id = p_id; END; $$ LANGUAGE plpgsql;
调用这些函数来执行插入和更新,就能自动帮你设置时间字段,完全符合你的要求。
3. MySQL 方案
方案A:计算列处理LastModifiedDateTime
和SQL Server类似,MySQL的虚拟计算列可以实时返回当前时间,适合LastModifiedDateTime:
ALTER TABLE your_table ADD COLUMN last_modified_datetime DATETIME AS (NOW()) VIRTUAL;
VIRTUAL类型的计算列不占用磁盘空间,每次查询都会自动取当前时间,刚好满足更新时自动刷新的需求;如果要持久化存储时间值,那还是得用存储过程。
方案B:存储过程封装操作
-- 先改分隔符,避免语法冲突 DELIMITER // CREATE PROCEDURE insert_your_table( IN p_other_column1 VARCHAR(50), IN p_other_column2 INT ) BEGIN INSERT INTO your_table (created_datetime, last_modified_datetime, other_column1, other_column2) VALUES (NOW(), NOW(), p_other_column1, p_other_column2); END // DELIMITER ; -- 更新用的存储过程 DELIMITER // CREATE PROCEDURE update_your_table( IN p_id INT, IN p_other_column1 VARCHAR(50), IN p_other_column2 INT ) BEGIN UPDATE your_table SET last_modified_datetime = NOW(), other_column1 = p_other_column1, other_column2 = p_other_column2 WHERE id = p_id; END // DELIMITER ;
最后提个关键的点:如果你的数据库支持内置行时间追踪(比如Azure SQL的时态表SYSTEM_TIME、BigQuery的分区时间),那可以直接开启这些特性来自动追踪创建和修改时间,这属于数据库原生支持的方案,完全符合你的“内置解决方案”要求。
内容的提问来源于stack exchange,提问作者Arun Gunaekaran

