console.error(`Unable to load nonexistent manifest entry ‘islands/voting-prompt’. Check that your file path is correct.`)

我想查找任何大于谓词中提供的时间的记录,该记录来自一个只有类型的 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.36333332024-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__1datetime与列匹配,因为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)CASTdatetime2(7)CAST2024-08-07 00:14:11.3632024-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。