【问题标题】:CTE Causing Conversion Failed when converting date and/or time from character string Error从字符串转换日期和/或时间时 CTE 导致转换失败 错误
【发布时间】:2014-02-28 17:04:21
【问题描述】:

我创建了一个非常简单的示例,显示了我在使用动态 SQL 进行更复杂的查询时遇到的问题,我无法弄清楚为什么 CTE 会导致错误,而标准版本不是。

使用 CTE 时出错:

从字符串转换日期和/或时间时转换失败。

我正在尝试通过我的动态查询实现以下目标: 标记与指定数据类型(本例中为日期)不匹配的记录。如果他们通过了该步骤,他们稍后会根据查找表进行检查,以验证它们是我期望的值(验证指定范围内的日期)。

 -- Table Setup
 CREATE TABLE #ValidDate 
 (
    V INT IDENTITY (1, 1) NOT NULL,
    VDate DATE NULL
 )

 INSERT INTO #ValidDate
 VALUES ('02/20/2014'), ('02/21/2014'), ('02/22/2014'), ('02/23/2014'), ('02/25/2014')

 CREATE TABLE #DatesToValidate 
 (
    I INT IDENTITY (1, 1) NOT NULL,
    IDate VARCHAR(30) NULL
 )

 INSERT INTO #DatesToValidate
 VALUES ('apple'), ('02/21/2014'), ('orange'), ('02/23/2014')

 CREATE TABLE #Errors
 (
    ID INT,
    Dates VARCHAR(30)
 )

 INSERT INTO #Errors
 SELECT *
 FROM #DatesToValidate
 WHERE ISDATE(IDate) <> 1

以下是标准查询(作品):

 SELECT *
 FROM #DatesToValidate
 WHERE I NOT IN (   SELECT ID
                    FROM #Errors)
AND IDate NOT IN (  SELECT VDate
                    FROM #ValidDate)

以下是 CTE(不起作用):

 ;WITH CTE AS
 (
    SELECT *
    FROM #DatesToValidate
    WHERE I NOT IN (    SELECT ID
                        FROM #Errors)
 )

 SELECT *
 FROM CTE
 WHERE IDate NOT IN (   SELECT VDate
                        FROM #ValidDate)

【问题讨论】:

  • 供将来参考 MySql 是一个与 SQL-Server 完全不同的 DBMS,不应将它们标记为相同。
  • 你能提供更多关于“不工作”的细节吗?

标签: sql sql-server-2008 tsql common-table-expression


【解决方案1】:

This SQL Fiddle 显示问题。这两个版本都不能保证工作。如果您交换and 中的条件顺序,则会导致转换失败。

and 版本发生在这种情况下工作的原因是短路。当第一个条件失败时,第二个条件不会运行。这是 SQL Server 可以利用的优化。在这种情况下确实如此,所以你认为它有效。

CTE 版本不起作用,因为无法保证操作的顺序。而 SQL Server 决定做一些不同的事情。即,它尝试将'apple' 评估为日期。

两者的正确解决方案是在比较之前进行转换。因为cast 可能不起作用,您需要小心。为此,您应该在 SQL Server 中使用case;它是唯一保证顺序评估的构造。

那么,试试这个:

;WITH CTE AS
 (
    SELECT *
    FROM DatesToValidate
    WHERE I NOT IN (    SELECT ID
                        FROM Errors)
 )
 SELECT *
 FROM CTE
 WHERE (case when isdate(IDate) = 1 then cast(IDate as date)
        end) NOT IN (   SELECT VDate
                        FROM ValidDate)

【讨论】:

    【解决方案2】:

    此特定部分失败,因为 VDatedate 类型列,IDatevarchar。所以你需要像cast(VDate as varchar(30)一样投射VDate,如下所示。

    在此处查看演示小提琴http://sqlfiddle.com/#!3/abfc0/7

    WHERE IDate NOT IN (SELECT VDate FROM ValidDate)  <--- Failing
    

    用这种方式试试你的 sql

    ;WITH CTE AS
     (
        SELECT *
        FROM DatesToValidate
        WHERE I NOT IN (    SELECT ID
                            FROM Errors)
     )
    
     SELECT *
     FROM CTE
     WHERE IDate NOT IN (SELECT cast(VDate as varchar(30))  <--- Cast Here
                            FROM ValidDate)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-17
      • 2017-12-07
      相关资源
      最近更新 更多