SQL Server中判断22:00–06:00跨日时段需用OR逻辑:HOUR(GETDATE()) >= 22 OR HOUR(GETDATE())

SQL Server 触发器不能直接用 HOUR(GETDATE()) 做跨日时段判断——必须用逻辑表达式,否则 22:00–06:00 这类区间永远判不中。
SQL Server 里怎么写非业务时间判断逻辑
SQL Server 没有 BETWEEN 跨零点的天然支持,HOUR(GETDATE()) BETWEEN 22 AND 6 是错的:因为 22 > 6,这个表达式恒为假。正确写法是拆成两段 OR:
-
HOUR(GETDATE()) >= 22(晚上10点及以后) HOUR(GETDATE()) (凌晨6点以前)
合起来就是:HOUR(GETDATE()) >= 22 OR HOUR(GETDATE()) 。注意这里用的是 ,不是 ,语义更清晰,也避免小时值边界混淆。如果业务要求精确到分钟(比如 22:30 开始禁写),就得换成 DATEPART(HOUR, GETDATE()) 配合 DATEPART(MINUTE, GETDATE()) 组合判断,但多数场景只控小时就够了。
AFTER UPDATE 触发器里怎么中止非法修改
SQL Server 不支持 SIGNAL,得用 RAISERROR + ROLLBACK TRANSACTION 组合来硬中断。关键点有三个:
- 必须在
IF EXISTS (SELECT 1 FROM inserted WHERE ...)判定后立刻RAISERROR,错误级别建议用 16(用户可捕获,又不会被当成系统严重错误) -
RAISERROR后必须跟ROLLBACK TRANSACTION,否则事务可能继续提交(尤其在嵌套事务中) - 别漏掉
RETURN或显式结束分支,避免后续逻辑误执行
示例片段:
GETDATE()
- 数据库服务器在东八区,但运维脚本从美国西海岸发起,
GETDATE()仍按服务器本地时间算——这没问题;但如果你的应用层日志用的是 UTC,而触发器用本地时间拦,两边“业务时间”定义就对不上 - 服务器时间没同步 NTP,偏差超过 10 分钟,可能导致半夜 5:58 的更新被放过,或早上 6:02 的合法操作被误杀
- SQL Server 2016+ 支持
SYSDATETIMEOFFSET(),能拿到带时区偏移的时间,但触发器里用它要小心:不同客户端连接带的SESSION_CONTEXT时区不影响SYSDATETIMEOFFSET(),它始终是服务器设置
最稳妥的做法是:统一把数据库服务器时区设为业务所在地标准时区(如 China Standard Time),并启用 NTP 自动校时。上线前用 SELECT GETDATE(), SYSDATETIMEOFFSET() 对照验证。
触发器里记录操作人和时间要注意什么
想审计谁在什么时候试图改数据,别直接用 SYSTEM_USER 或 CURRENT_USER——它们返回的是数据库登录名,不是应用层真实操作人。更现实的做法是:
- 让应用在连接字符串里加
Application Name=xxx,然后在触发器里查APP_NAME(),至少能区分是后台任务还是前端服务连的 - 如果应用已支持传递上下文,优先用
SESSION_CONTEXT(N'UserId')(需提前sp_set_session_context设置),这是 SQL Server 2016+ 提供的安全传参方式 - 记录时间统一用
GETDATE(),别用GETUTCDATE(),否则和业务时间逻辑脱节
日志表本身要轻量:只存 table_name、pk_id、operation_type、app_name、attempt_time 五列即可,避免在触发器里做 JOIN 或子查询——会拖慢所有 UPDATE。
跨日时段判断是触发器里最容易写错的一环,看似简单,实则对逻辑严谨性要求极高。哪怕只漏一个 OR 或写反大小于号,整个防护就形同虚设。










