“转换失败”CTE出错

时间:2017-01-08 08:26:14

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

这是我用来获取年龄在25到34岁之间的所有用户的SQL Server 2012查询的精简版本。在我的表中,

  1. “反馈”列的类型为VarChar,并以dd-mm-yyyy格式将用户的出生日期存储为VarChar。
  2. “FeedbackDate”列的类型为DateTime,基本上是用户以“反馈”形式告诉我他的DOB的日期,我将其存储在“反馈”列中。
  3. WITH AgeCTE AS
        (
        SELECT
            CASE
                WHEN DATEADD(yy, DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate), CONVERT(DATETIME, Feedback)) < FeedbackDate
                THEN DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate)
            ELSE DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate) - 1
        END AS Age
        FROM FeedbackTable
        )
        SELECT COUNT(*) AS [25To34] FROM AgeCTE WHERE (Age >= 25) AND (Age <= 34)
    

    执行此查询时,我收到以下错误:

    Conversion failed when converting date and/or time from character string.
    

    此外,当我尝试执行内部查询时,它会成功执行,这表明在执行内部查询之前,日期的格式不是问题。

    例如,当我执行以下查询时:

    SELECT
    CASE
        WHEN DATEADD(yy, DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate), CONVERT(DATETIME, Feedback)) < FeedbackDate
        THEN DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate)
        ELSE DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate) - 1
        END AS Age
    FROM FeedbackTable
    

    我得到一个输出:

    年龄

    23 33 35 8 等...

    如果省略最后一个WHERE子句,即使是CTE的整个查询也能正常工作。具体来说,如果我删除部分

    WHERE (Age >= 25) AND (Age <= 34)
    

    并执行以下查询:

    WITH AgeCTE AS
    (
        SELECT
            CASE
                WHEN DATEADD(yy, DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate), CONVERT(DATETIME, Feedback)) < FeedbackDate
                THEN DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate)
            ELSE DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate) - 1
        END AS Age
        FROM FeedbackTable
    )
    SELECT COUNT(*) AS [25To34] FROM AgeCTE
    

    我得到以下输出:

    25To34

    9

    我无法理解WHERE子句的问题。我在互联网上的某处读到它可能是短路的,但是,我无法弄清楚如何。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

首先:以字符串格式存储日期总是一个坏主意......

其次:您的格式dd-mm-yyyy - 甚至更糟 - 文化特定。在没有第三个参数的情况下使用CONVERT()是赌博。这是否有效取决于您的系统设置。

首次尝试时,我会添加相应的代码Find details here

CONVERT(DATETIME, Feedback, 105)

如果仍然遇到问题,可以使用此方法(SQL-Server 2012 +)

SELECT * 
FROM YourTable 
WHERE TRY_CONVERT(DATETIME,Feedback) IS NULL 

TRY_CONVERT是一个非常新的函数,如果转换失败则返回NULL。

答案 1 :(得分:0)

我相信您可以使用ISDATE()检查并查看是否可以转换该值。如果没有,那么您可以返回零,并且该行将从您的查询中排除。

WITH AgeCTE AS
(
  SELECT
    CASE
        WHEN DATEADD(yy, DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate), CONVERT(DATETIME, Feedback)) < FeedbackDate
        THEN DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate)
    ELSE 
      CASE 
        WHEN ISDATE(Feedback) = 1 
        THEN DATEDIFF(yy, CONVERT(DATETIME, Feedback), FeedbackDate) - 1
      ELSE
        0
      END
    END AS Age
  FROM FeedbackTable
)
SELECT COUNT(*) AS [25To34] 
FROM AgeCTE 
WHERE (Age >= 25) AND (Age <= 34)

我会回应@Shnugo所说的内容,你应该在CONVERT语句中使用隐式格式参数,而不是使用VARCHAR来存储日期。