简体   繁体   中英

Strange issue when converting VarChar(max) to DATE or DATETIME in SQL Server 2008

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

This is my original sql query. It seems to work fine with our data in our dev environment. In production however I get the following error. "Msg 241, Level 16, State 1, Line 1 Conversion failed when converting date and/or time from character string.". Now if I remove the convert function in the SELECT and just output AttributeData.Keyword it will work fine. If I leave that alone and remove the convert function in the where clause it will work fine. It will not work if they both exist though.

Any ideas what could cause this? I have tried CAST and I have tried using a specific date style. Our dates generally look like yyyymmdd. An example is '20110318'. If I replace AttributeData.Keyword with this string it will also fail. I really have no idea what is going on here.

Here is an example of a query that works.

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

In SQL Server no particular order of evaluation is guaranteed except for CASE statements so it may well be doing the CONVERT(DATE, AttributeData.Keyword) before the ISDATE(AttributeData.Keyword) = 1 filter (you can confirm this by looking at the execution plans).

To get around this you can replace CONVERT(DATE, AttributeData.Keyword) with

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

So can you try

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  

You could also try adding

(ISDATE(AttributeData.Keyword) = 1)

as a join condition on AttributeData, but I think you are still not guaranteed order of execution there.

And this seems to work fine....

    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

It appears that Martin was correct in that the SQL optimizer is reordering which parts get evaluated first which means converts are happening before ISDATE so I am actually processing invalid dates. ATM the only way I know to fix this is to use a temp table and evaluate without the convert in the select statement until I am ready to return the results...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM