【问题标题】:SQL Server DateTime conversion failureSQL Server 日期时间转换失败
【发布时间】:2008-08-26 14:01:43
【问题描述】:

我有一个包含 100 万多条记录的大表。不幸的是,创建表格的人决定将日期放在varchar(50) 字段中。

我需要做一个简单的日期比较-

datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31

但它在convert() 上失败:

Conversion failed when converting datetime from character string.

显然那个领域有什么不喜欢的东西,而且记录太多了,我不能光看它。如何正确清理整个日期字段,使其不会在convert() 上失败?这是我现在拥有的:

select count(*)
from MyTable
where
    isdate(lastUpdate) > 0
    and datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31

@SQLMenace

我不关心这种情况下的性能。这将是一次查询。将表格更改为日期时间字段不是一种选择。

@Jon Limjap

我已经尝试添加第三个参数,它没有任何区别。


@SQLMenace

问题很可能是数据是如何存储的,只有两种安全格式; ISO YYYYMMDD; ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm(无空格)

isdate() 支票不会解决这个问题吗?

我不需要 100% 的准确率。我只想获取过去 30 天的大部分记录。


@SQLMenace

select isdate('20080131') -- returns 1
select isdate('01312008') -- returns 0

@Brian Schkerke

将 CASE 和 ISDATE 放在 CONVERT() 函数中。

谢谢!做到了。

【问题讨论】:

  • 您没有提到 varchar 字段的日期格式。它们的格式是否一致?了解格式将有助于解决问题。

标签: sql-server datetime


【解决方案1】:

CASEISDATE 放在CONVERT() 函数中。

SELECT COUNT(*) FROM MyTable
WHERE
    DATEDIFF(dd, CONVERT(DATETIME, CASE IsDate(lastUpdate)
        WHEN 1 THEN lastUpdate
        ELSE '12-30-1899'
    END), GetDate()) < 31

'12-30-1899' 替换为您选择的默认日期。

【讨论】:

    【解决方案2】:

    如何编写一个游标来循环遍历内容,尝试为每个条目进行强制转换?当发生错误时,输出问题记录的主键或其他识别详细信息。 我想不出一种基于集合的方法来做到这一点。

    不完全基于集合,但如果 100 万行中只有 3 行是坏的,它会为你节省很多时间

    select * into BadDates
    from Yourtable
    where isdate(lastUpdate) = 0
    
    select * into GoodDates
    from Yourtable
    where isdate(lastUpdate) = 1
    

    然后只需查看 BadDates 表并修复它

    【讨论】:

      【解决方案3】:

      如果 ISDATE() 确实首先执行,则 ISDATE() 将处理格式不正确的行。但是,如果您查看执行计划,您可能会发现首先应用了 DATEDIFF 谓词 - 这就是造成您痛苦的原因。

      如果您使用 SQL Server Management Studio,请点击 CTRL+L 来查看特定查询的估计执行计划。

      请记住,SQL 不是一种过程语言,短路逻辑可能会起作用,但前提是您要小心应用它。

      【讨论】:

        【解决方案4】:

        写一个游标来循环遍历内容,尝试对每个条目进行强制转换怎么样?

        发生错误时,输出问题记录的主键或其他识别详细信息。

        我想不出一种基于集合的方式来做到这一点。

        编辑 - 是的,我忘记了 ISDATE()。绝对比使用游标更好的方法。 +1 到 SQLMenace。

        【讨论】:

          【解决方案5】:

          在您的转换调用中,您需要指定第三个样式参数,例如,存储为 varchar 的日期时间的格式,如本文档中所述:CAST and CONVERT (T-SQL)

          【讨论】:

            【解决方案6】:

            打印出记录。把硬拷贝给决定使用 varchar(50) 的白痴,让他们找到问题记录。

            下次他们可能会看到选择合适的数据类型的意义。

            【讨论】:

              【解决方案7】:

              问题是最有可能的数据是如何存储的,仅存在两个安全格式 P>

              ISO YYYYMMDD P>

              ISO 8601 YYYY-MM-DD THH:MM:SS:MMM(没有空格) P>

              这将工作,无论你的语言是什么。 P>

              您可能需要做一个SET DATEFORMAT YMD(或任何数据存储为),使其工作 P>

              【讨论】:

                【解决方案8】:

                isdate() 检查不会解决这个问题吗?

                运行这个看看会发生什么

                select isdate('20080131')
                select isdate('01312008')
                

                【讨论】:

                  【解决方案9】:

                  我确信由于任何遗留系统要求,更改表/列可能不是一个选项,但是如果您使用的是更新版本的sql,那么你甚至可以使用索引视图?

                  【讨论】:

                    【解决方案10】:

                    我建议清理混乱并将列更改为日期时间,因为做这样的事情

                    WHERE datediff(dd, convert(datetime, lastUpdate), getDate()) < 31
                    

                    不能使用索引,它会比你有一个 datetime 列慢很多倍,n 和 did

                    where lastUpdate > getDate() -31
                    

                    当然你还需要考虑小时和秒

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-02-12
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多