我想查找任何大于谓词中提供的时间的记录,该记录来自一个只有类型的 C# Web 应用程序DateTime
。但是,SQL Server 返回的行等于提供的谓词值。为什么会这样?该ShipDateTimeUTC
列是一种datetime
数据类型。
DECLARE @p__linq__1 datetime2(7) = '2024-08-07 00:14:11.3630000';
SELECT
[OrderHeaderId],
Id,
[ShipDateTimeUTC]
FROM
[dbo].[ShippingContainerHeader]
WHERE
[ShipDateTimeUTC] > @p__linq__1;
以下是结果,您可以看到 ShipDateTimeUTC 与谓词值匹配。我不希望它被包括在内。为什么它会被包括在结果中?
最佳答案
2
ShipDateTimeUTC
如果是一种数据类型,您将得到这种行为datetime
。
有一个恼人的(†)“设计”行为,当转换为datetime2(7)
诸如2024-08-07 00:14:11.363
转换为2024-08-07 00:14:11.3633333
(2024-08-07 00:14:11.367
并将转换为2024-08-07 00:14:11.3666667
)的值时
经过这次隐式转换2024-08-07 00:14:11.3633333
大于2024-08-07 00:14:11.3630000
。
您应该将数据类型更改@p__linq__1
为datetime
与列匹配,因为WHERE
无论如何都应避免子句中的隐式转换。
如果由于某种原因您陷入困境,datetime2(7)
那么您需要更改要使用的值2024-08-07 00:14:11.3633333
来解决这个问题。
)的原理是
转换为具有更高精度的日期/时间类型时,精度会得到提高。请注意,日期时间值存储为表示 1/300 秒的刻度。较新的时间和 datetime2 类型存储离散的数字,其中数字的数量与精度相匹配。
我已经检查了 SQL Server 2000 在线书籍,其中确实提到datetime
1753 年 1 月 1 日至 9999 年 12 月 31 日的日期和时间数据,精确到三百分之一秒(相当于 3.33 毫秒或 0.00333 秒)。值四舍五入为 .000、.003 或 .007 秒的增量
因此,尽管这种行为可能会导致意外结果,但它与始终记录的行为一致。
3
-
在我的实际场景中,谓词值来自从
DateTime
同一数据库列检索此 sql 的 C# web 应用程序,然后必须将其四舍五入为.3630000
,而 SQL Server 四舍五入为.3633333
。因此,当您包含 的谓词值时datetime2(7)
,SQL Server 将首先将数据库值转换为datetime2(7)
,然后应用谓词条件,而不是相反地将谓词向下转换以匹配列数据类型?
– -
@crichavin – 是的。
datetime2
具有比更高的数据类型优先级,datetime
因此转换以这种方式进行。learn.microsoft.com/en- /sql/t-sql/data-types/… – 通常,这也是一个坏消息,因为它可以阻止在列上发生索引查找(尽管看起来在这种情况下仍有一些逻辑允许查找)。理想情况下,您需要让参数数据类型与列相同
–
-
当被索引时,执行计划中
ShipDateTimeUTC
实际上没有显示任何运算符。它看起来就像一个带有与值进行比较的谓词的正常搜索。因此在实践中,这可能是通过两种数据类型之间的一些比较器逻辑来实现的,这些比较器逻辑保持与将要实现的语义相同的语义(并且不将datetime 视为等于datetime2)CAST
datetime2(7)
CAST
2024-08-07 00:14:11.363
2024-08-07 00:14:11.3630000
–
|
混合数据类型是个坏主意。如果数据库类型是 datetime,那么变量应该是 datetime。
您遇到的问题是,对于 ShipDateTimeUTC,将 datetime 隐式转换为 datetime2 将产生 2024-08-07 00:14:11.3633333,大于 2024-08-07 00:14:11.3630000。
|
|