我有一张包含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
在这种情况下,我并不关心性能。这将是一次性查询。将表格更改为日期时间字段不是一种选择。
我尝试添加第三个参数,但没有区别。
问题很可能是数据的存储方式,只有两种安全格式; ISO YYYYMMDD; ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm(无空格)
isdate()
检查不会照顾这个吗?
我不需要100%准确度。我只想获得过去30天的大部分记录。
select isdate('20080131') -- returns 1
select isdate('01312008') -- returns 0
将CASE和ISDATE放在CONVERT()函数中。
谢谢!这样做了。
答案 0 :(得分:8)
将CASE
和ISDATE
放入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,那你甚至可以使用索引视图?