即使 CTE 应该只有好的日期,也会出现转换错误

gre*_*reg 1 sql sql-server string datetime where-clause

使用 SQL Server - 我的问题是:尽管 CTE 只有具有正确日期的行,但我如何仍然收到转换错误?

如果我只使用具有有效日期的行创建 CTE……我仍然收到错误消息。

WITH goodDates AS
(
    SELECT * 
    FROM impExpRaw2 
    WHERE ISDATE(dateofservice) = 1 
      AND DateofService <> '' 
      AND DateofService IS NOT NULL
)
SELECT * 
FROM goodDates 
WHERE DATEDIFF(d, '7/31/2020', dateofservice) > 0 
Run Code Online (Sandbox Code Playgroud)

这会产生以下错误消息,如果该字段中有“2/31/2020”或“cat”之类的日期,我会期望这些消息...

消息 241,级别 16,状态 1,行 293
从字符串转换日期和/或时间时转换失败。

有点令人沮丧,因为我找不到任何带有错误日期的行。

我可以选择一个临时表,然后执行 dateDiff 并且一切正常。对我来说,这确实排除了带有隐藏 chr(0) 或嵌入其中的某些内容的疯狂数据或字段。

select * 
into #gd 
from impExpRaw2 
where isdate(dateofservice) = 1   

select * 
from #gd 
where datediff (d, '7/31/2020', dateofservice) > 0 
Run Code Online (Sandbox Code Playgroud)

这是今天在我的开发机器上发生的,但它也发生在较新的版本上

有兴趣的人的版本信息

Microsoft SQL Server 2016 (RTM-GDR) (KB3164398) - 13.0.1708.0 (X64)   
Copyright (c) Microsoft Corporation  
Standard Edition (64-bit) on Windows Server 2012 R2 Standard 6.3 <X64> (Build 9600: ) 
Run Code Online (Sandbox Code Playgroud)

GMB*_*GMB 7

我会推荐try_cast()而不是isdate():它更可靠,因为它实际上试图将字符串强制转换为日期,而不是依赖一些复杂的启发式方法。

您可以将查询表述为:

select *
from impExpRaw2
where try_cast(dateofservice as datetime) >= '20200801'
Run Code Online (Sandbox Code Playgroud)

try_cast()null转换失败时返回,不满足where谓词。请注意,使用此方法,您不需要显式过滤掉null或清空值(转换函数将null很好地返回值)。

最后:在声明日期文字时,使用 format 更安全YYYYMMDD,SQL Server 始终将其识别为日期,而不管区域设置如何。