SQL Server DateTime转换失败

时间:2008-08-26 14:01:43

标签: sql-server datetime

我有一张包含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()函数中。

谢谢!这样做了。

10 个答案:

答案 0 :(得分:8)

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'替换为您选择的默认日期。

答案 1 :(得分:3)

  

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

不完全基于设定,但如果100万只中只有3行不好,它会为您节省大量时间

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

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

然后只需查看BadDates表并修复

答案 2 :(得分:2)

ISDATE()将处理未正确格式化的行,如果它确实是先执行的话。但是,如果你查看执行计划,你可能会发现DATEDIFF谓词首先被应用 - 这是你痛苦的原因。

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

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

答案 3 :(得分:1)

如何编写游标来遍历内容,为每个条目尝试强制转换?

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

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

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

答案 4 :(得分:0)

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

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

不能使用索引,它会比你有一个datetime colum慢很多倍,n并且

where lastUpdate > getDate() -31

您还需要考虑课程的小时和秒数

答案 5 :(得分:0)

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

答案 6 :(得分:0)

打印出记录。给那些决定使用varchar(50)并要求他们找到问题记录的白痴一份硬拷贝。

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

答案 7 :(得分:0)

问题很可能是如何存储数据,只有两种安全格式

ISO YYYYMMDD

ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm(无空格)

无论你的语言是什么,这些都会有用。

您可能需要执行SET DATEFORMAT YMD(或存储数据的任何内容)才能使其正常工作

答案 8 :(得分:0)

  

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

运行此以查看会发生什么

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

答案 9 :(得分:0)

我确信由于任何遗留系统要求,更改表/列可能不是一个选项,但您是否考虑过创建一个内置日期转换逻辑的视图,如果您使用的是更新版本的sql,那你甚至可以使用索引视图?