Ast*_*tor 4 sql-server t-sql datetime date sql-server-2016
在其中一个存储过程中,我需要捕获实时事件的持续时间。保证永远不会超过 24 小时,因此结果列的数据类型选择为TIME(3)(映射到TimeSpan应用程序端)。计算过程如下:
update tbEvent set tWait= @dtEvent - dEvent - tEvent [where idEvent = @idEvent]
Run Code Online (Sandbox Code Playgroud)
此处dEvent和tEvent先前设置为dtEvent(原始事件@dtEvent的时刻)的日期和时间部分,并且是后续关闭事件的时刻。因此,我从 DATETIME 变量中减去 DATE 和 TIME 列值,并将结果填充到 TIME 列中。
[合理吗?] 预期行为: SQL 将每个表达式项隐式转换为 DATETIME,执行减法,然后通过简单地删除 DATE 部分将结果隐式转换为 TIME。 这一直有效! 嗯, - 到目前为止..
一个更新脚本突然在 SQL 2016 (13.0.1742.0) 上产生了一个错误:
System.Data.SqlClient.SqlException (0x80131904):
The data types datetime and date are incompatible in the subtract operator.
Error Number:402,State:1,Class:16
Run Code Online (Sandbox Code Playgroud)
但是相同的脚本在 2008 R2 (10.50.2500.0) 和 2019 (15.0.2080.9) 上运行良好!
这个存储过程已经用这段代码更新了很长一段时间(几年),对它的后续修改(用那个代码)已经多次成功地应用于所有这些登台服务器。是什么赋予了?
发现的第一个有希望且中肯的解释是这篇文章(从 2013 年开始),它指出从 SQL Server 2012 开始,Microsoft 不允许在没有显式转换的情况下从 DATETIME 中添加/减去 TIME(尽管没有给出直接参考) . MS 自己的文档(DATETIME、DATE、TIME)甚至没有提到直接算术运算。
正如建议的那样,解决方案很简单 - 使用显式转换为 DATETIME(适用于所有版本):
update tbEvent set tWait= @dtEvent - cast(dEvent as datetime) - cast(tEvent as datetime)
Run Code Online (Sandbox Code Playgroud)
我没有 2012 年或 2014 年和 2017 年的版本来进行完整检查。但我确实有这些问题:
QA 团队表示,2016 年盒子上没有最近的 SQL Server 更新。
2021 年 8 月 27 日:更新
Hannah 的答案是正确的(涵盖 Q#1,2):
不久前,2016 年 box DB 的兼容性级别设置为 130(即 2016 年)。
初始值为 100 (2008 R2),这就是为什么我们的 2019 盒子没有触发错误的原因。
Q#3 保持打开状态。 我相信它是相关的,并希望了解完整性。
Han*_*non 10
正如此简单测试所证明的那样,该错误确实发生在 SQL Server 2019 上。
让我们先检查服务器版本:
SELECT [SQL Server Version] = @@VERSION;
Run Code Online (Sandbox Code Playgroud)
结果:
| SQL Server 版本 |
|---|
| Microsoft SQL Server 2019 (RTM-CU12) (KB5004524) - 15.0.4153.1 (X64) |
| 2021 年 7 月 19 日 15:37:34 |
| 版权所有 (C) 2019 微软公司 |
| Linux (Red Hat Enterprise Linux) 上的开发人员版(64 位) |
测试代码:
DECLARE @dt datetime = GETDATE();
DECLARE @d date = GETDATE();
SELECT [datetime] = @dt
, [date] = @d;
Run Code Online (Sandbox Code Playgroud)
结果:
| 约会时间 | 日期 |
|---|---|
| 2021-08-19 16:12:10.770 | 2021-08-19 |
错误行为:
DECLARE @dt datetime = GETDATE();
DECLARE @d date = GETDATE();
SELECT @dt - @d;
Run Code Online (Sandbox Code Playgroud)
和错误:
消息 402,级别 16,状态 1,第 7 行 数据类型 datetime 和 date 在减法运算符中不兼容。
如果我在 SQL Server 2019 中创建兼容级别为 100(即 SQL Server 2008 R2)的数据库,则代码运行良好:
CREATE DATABASE date_test;
ALTER DATABASE date_test SET COMPATIBILITY_LEVEL = 100;
USE date_test;
DECLARE @dt datetime = GETDATE();
DECLARE @d date = GETDATE();
SELECT @dt - @d;
Run Code Online (Sandbox Code Playgroud)
结果:
| (无列名) |
|---|
| 1900-01-01 16:15:21.430 |
因此,似乎有人更改了数据库的兼容性级别。用这个语句检查一下:
SELECT d.name
, d.compatibility_level
FROM sys.databases d
WHERE d.database_id = DB_ID();
Run Code Online (Sandbox Code Playgroud)
结果:
| 姓名 | 兼容性_级别 |
|---|---|
| 日期_测试 | 100 |
一个datetime值可以隐式转换为一个time值,因为SQL Server有内置的隐式转换代码,要做到这一点,因为有不明确没有机会时,只需丢弃值的日期部分。查看图表的隐式转换,显示可以隐式转换的内容以及需要显式转换语句的内容。
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |