简体   繁体   English

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

[英]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. 这是我原来的SQL查询。 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.". “从字符串转换日期和/或时间时,消息241,级别16,状态1,行1转换失败。” Now if I remove the convert function in the SELECT and just output AttributeData.Keyword it will work fine. 现在,如果我删除SELECT中的转换函数并输出AttributeData.Keyword,它将正常工作。 If I leave that alone and remove the convert function in the where clause it will work fine. 如果我单独留下并删除where子句中的convert函数,它将正常工作。 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. 我试过CAST,我尝试过使用特定的日期样式。 Our dates generally look like yyyymmdd. 我们的日期通常看起来像yyyymmdd。 An example is '20110318'. 一个例子是'20110318'。 If I replace AttributeData.Keyword with this string it will also fail. 如果我用此字符串替换AttributeData.Keyword,它也将失败。 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). 在SQL Server中,除了CASE语句之外,没有保证特定的评估顺序,因此它可能在ISDATE(AttributeData.Keyword) = 1过滤器之前执行CONVERT(DATE, AttributeData.Keyword) (您可以通过查看执行来确认这一点)计划)。

To get around this you can replace CONVERT(DATE, AttributeData.Keyword) with 要解决此问题,您可以使用替换CONVERT(DATE, AttributeData.Keyword)

     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. 作为AttributeData的连接条件,但我认为你仍然不能保证执行顺序。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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