为什么在TSQL中会出现日期时间转换错误?

为什么在TSQL中会出现日期时间转换错误?,tsql,datetime,type-conversion,Tsql,Datetime,Type Conversion,我知道关于这个话题有很多问题,甚至是我刚才问自己的一个问题()。现在我遇到了另一个问题,我自己和我的同事都不知道这种奇怪行为的原因是什么 我们有一个相对简单的SQL语句,如下所示: SELECT CONVERT(DATETIME, SUBSTRING(MyText, CHARINDEX('Date:', MyText) + 8, 16) AS MyDate, SomeOtherColumn, ... FROM MyTable INNER JOIN MyOtherT

我知道关于这个话题有很多问题,甚至是我刚才问自己的一个问题()。现在我遇到了另一个问题,我自己和我的同事都不知道这种奇怪行为的原因是什么

我们有一个相对简单的SQL语句,如下所示:

SELECT
    CONVERT(DATETIME, SUBSTRING(MyText, CHARINDEX('Date:', MyText) + 8, 16) AS MyDate,
    SomeOtherColumn,
    ...
FROM
    MyTable
INNER JOIN MyOtherTable
    ON MyTable.ID = MyOtherTable.MyTableID
WHERE
    MyTable.ID > SomeValue AND
    MyText LIKE 'Date: %'
这不是我的数据库,也不是我的SQL语句,我没有创建在varchar列中存储日期时间值的伟大模式,所以请忽略这一点

我们现在面临的问题是SQL转换错误241(“从字符串转换日期和/或时间时转换失败”)

现在我知道查询优化程序可能会更改执行计划,即在尝试转换后,WHERE子句可能会用于过滤结果,但真正奇怪的是,当我删除所有WHERE子句时,我没有收到任何错误

当我在上面的语句中添加一行时,也没有出现任何错误,如下所示:

SELECT
    MyText, -- This is the added line
    CONVERT(DATETIME, SUBSTRING(MyText, CHARINDEX('Date:', MyText) + 8, 16) AS MyDate,
    ...
一旦我删除它,我就会再次出现转换错误。手动检查MyText列中的值而不尝试转换它们并不表明存在任何可能导致问题的记录

转换错误的原因是什么?为什么在选择列作为select语句的一部分时没有遇到它

更新

这里是执行计划,虽然我认为它不会有帮助。

有时,SQL Server会在转换过程中提前推送转换操作,从而进行积极的优化。(不应如此。请参见“连接”上的,作为示例)

当您只需选择:

CONVERT(DATETIME, SUBSTRING(MyText, CHARINDEX('Date:', MyText) + 8, 16)
然后优化器决定,它可以在从表中读取数据的点(重要的是,在
WHERE
子句过滤器之前或同时)作为表/索引扫描或查找的一部分执行此转换。然后,查询的其余部分可以只使用转换后的值

当您选择:

MyText, -- This is the added line
CONVERT(DATETIME, SUBSTRING(MyText, CHARINDEX('Date:', MyText) + 8, 16)
它决定以后再进行转换。重要的是,现在的转换(通过偶然事件)发生在
WHERE
子句过滤器之后,根据权利,该过滤器应该在尝试转换之前过滤所有行


处理这一问题的唯一安全方法是在尝试转换之前强制进行过滤。如果您没有处理聚合,则
大小写
表达式可能足够安全:

SELECT CASE WHEN MyText LIKE 'Date: %' THEN CONVERT(DATETIME, SUBSTRING(MyText, CHARINDEX('Date:', MyText) + 8, 16) END

否则,更安全的选择是将查询拆分为两个单独的查询,并将中间结果存储在临时表或表变量中(视图、CTE和子查询不计算在内,因为优化器可以“看穿”此类结构)

在没有where子句的情况下运行查询时,
第一行的
myText
列的值是多少?为什么
CHARINDEX('Date:',myText)
当您的
LIKE
子句保证
MyText
Date:
开头时?@Kaf:Data类似于:Ping未达到11.22.33.44:11.22.33.44是0%可达到1。尝试日期:31.12.2000 12:34:56 IP:11.22.33.44这不是我的东西生成的。@Damien:我知道,但这是如何“开发”的,但这与转换错误无关。我想这是你的数据。很容易确认您是否可以给我们一个没有where的运行和where失败的测试。谢谢,这是我在上面链接的另一个问题的答案中所描述的。但是当我根本不使用WHERE子句时,我就不会得到错误。这很奇怪,,当我完全忽略WHERE子句而与WHERE子句进行比较时,我的数据怎么可能看起来更少呢?生成查询计划并将其编辑到您的问题中,以便进行更详细的查看。今晚我将更新问题,因为由于WTS互联网限制,我无法上传计划截图。我上传了工作的图像执行计划时,导致错误的查询没有生成一个。第一个版本太小-认为您可以以某种方式看到原始版本。我现在上传了两部分。