在SQL Server 2008中将VarChar(max)转换为DATE或DATETIME时出现奇怪的问题

时间:2011-03-21 23:57:01

标签: .net sql-server datetime date

SELECT     Files.URL, Files.MD5, Files.Thumbnail, Files.Title, CONVERT(DATE, AttributeData.Keyword) AS DateUpdated, Attributes.Name AS DateType, 
                      Metadata.metadata
FROM         Files INNER JOIN
                      Metadata ON Files.ID = Metadata.FileID INNER JOIN
                      FilesToAttributeData ON Files.ID = FilesToAttributeData.FileID INNER JOIN
                      AttributeData ON FilesToAttributeData.AttributeDataID = AttributeData.ID INNER JOIN
                      Attributes ON AttributeData.AttributeID = Attributes.ID
WHERE       (Files.GeneralSearch = 1) AND 
            (Attributes.Name = 'Process Date' OR Attributes.Name = 'Publish Date') AND 
            (ISDATE(AttributeData.Keyword) = 1) AND 
            (CONVERT(DATE, AttributeData.Keyword) > DATEADD(DAY, - 90, GETDATE()))
ORDER BY DateUpdated DESC

这是我原来的sql查询。它似乎可以在我们的开发环境中使用我们的数据。但在生产中我收到以下错误。 “Msg 241,Level 16,State 1,Line 1 从字符串转换日期和/或时间时转换失败。“。现在,如果我删除SELECT中的转换函数并输出AttributeData.Keyword它将正常工作。如果我单独留下并删除where子句中的转换函数如果它们都存在,它将无法正常工作。

任何可能导致此问题的想法?我试过CAST,我尝试过使用特定的日期样式。我们的日期通常看起来像yyyymmdd。一个例子是'20110318'。如果我用此字符串替换AttributeData.Keyword,它也将失败。我真的不知道这里发生了什么。

以下是一个有效的查询示例。

SELECT     (AttributeData.Keyword) AS DateUpdated, Attributes.Name AS DateType

    FROM         Files INNER JOIN
                          Metadata ON Files.ID = Metadata.FileID INNER JOIN
                          FilesToAttributeData ON Files.ID = FilesToAttributeData.FileID INNER JOIN
                          AttributeData ON FilesToAttributeData.AttributeDataID = AttributeData.ID INNER JOIN
                          Attributes ON AttributeData.AttributeID = Attributes.ID
    WHERE       (Files.GeneralSearch = 1) AND 
                (Attributes.Name = 'Process Date' OR Attributes.Name = 'Publish Date') AND 
                (ISDATE(AttributeData.Keyword) = 1) AND 
                (CONVERT(DATE, AttributeData.Keyword) > DATEADD(DAY, - 90, GETDATE()))
    ORDER BY DateUpdated DESC

    DateUpdated DateType
    20110318    Process Date
    20110318    Process Date
    20110315    Process Date
    20110315    Process Date
    20110303    Process Date
    20110303    Publish Date
    20110302    Process Date
    20110301    Process Date
    20110301    Publish Date
    20110225    Process Date
    20110223    Process Date
    20110201    Publish Date
    20110201    Process Date
    20110127    Process Date
    20110118    Publish Date
    20110101    Publish Date
    20110101    Publish Date
    20101231    Process Date
    20101231    Publish Date

3 个答案:

答案 0 :(得分:3)

在SQL Server中,除了CASE语句之外,没有任何特定的评估顺序,因此它可能会在CONVERT(DATE, AttributeData.Keyword)过滤器之前执行ISDATE(AttributeData.Keyword) = 1(您可以通过查看执行计划)。

要解决此问题,您可以将CONVERT(DATE, AttributeData.Keyword)替换为

     CASE
           WHEN ISDATE(AttributeData.Keyword) = 1 THEN
           CONVERT(DATE, AttributeData.Keyword)
         END

所以你可以尝试

SELECT Files.URL,
       Files.MD5,
       Files.Thumbnail,
       Files.Title,
       CASE
         WHEN ISDATE(AttributeData.Keyword) = 1 THEN
         CONVERT(DATE, AttributeData.Keyword)
       END             AS DateUpdated,
       Attributes.Name AS DateType,
       Metadata.metadata
FROM   Files
       INNER JOIN Metadata
         ON Files.ID = Metadata.FileID
       INNER JOIN FilesToAttributeData
         ON Files.ID = FilesToAttributeData.FileID
       INNER JOIN AttributeData
         ON FilesToAttributeData.AttributeDataID = AttributeData.ID
       INNER JOIN Attributes
         ON AttributeData.AttributeID = Attributes.ID
WHERE  ( Files.GeneralSearch = 1 )
       AND ( Attributes.Name = 'Process Date'
              OR Attributes.Name = 'Publish Date' )
       AND ( CASE
               WHEN ISDATE(AttributeData.Keyword) = 1 THEN
               CONVERT(DATE, AttributeData.Keyword)
             END > DATEADD(DAY, -90, GETDATE()) )
ORDER  BY DateUpdated DESC  

答案 1 :(得分:1)

您也可以尝试添加

(ISDATE(AttributeData.Keyword) = 1)

作为AttributeData的连接条件,但我认为你仍然不能保证执行顺序。

答案 2 :(得分:0)

这似乎工作得很好......

    DECLARE @tempFiles TABLE(DateUpdated varchar(MAX))

INSERT INTO @tempFiles(DateUpdated)
SELECT     AttributeData.Keyword AS DateUpdated
FROM         Files INNER JOIN
                      Metadata ON Files.ID = Metadata.FileID INNER JOIN
                      FilesToAttributeData ON Files.ID = FilesToAttributeData.FileID INNER JOIN
                      AttributeData ON FilesToAttributeData.AttributeDataID = AttributeData.ID INNER JOIN
                      Attributes ON AttributeData.AttributeID = Attributes.ID
WHERE       (Files.GeneralSearch = 1) AND 
            (Attributes.Name = 'Process Date' OR Attributes.Name = 'Publish Date') AND 
            (ISDATE(AttributeData.Keyword) = 1) AND 
            (CONVERT(DATETIME, AttributeData.Keyword, 112) > DATEADD(DAY, - 90, GETDATE()))
ORDER BY DateUpdated DESC

SELECT CONVERT(DATE, DateUpdated) FROM @tempFiles

看来Martin是正确的,因为SQL优化器正在重新排序哪些部分首先被评估,这意味着在ISDATE之前发生转换,所以我实际上正在处理无效日期。 ATM我知道解决这个问题的唯一方法就是使用临时表并在select语句中进行评估,直到我准备好返回结果...