在给定的场景中,我们有两个表:
以下陈述应更新所有"字段的所有历史值"可转换为" DateTime":
BEGIN TRAN
UPDATE c
SET c.OldValue = CONVERT(varchar(23), CONVERT(DATETIME, c.OldValue, 101), 21)
FROM ChangeLog c
WHERE c.FieldID IN ( SELECT v.FieldID
FROM ViewFields v
WHERE FieldDataType IN (4,5,6))
执行语句时,我收到以下错误消息:
Msg 241,Level 16,State 1,Line 5 从字符串转换日期和/或时间时转换失败。
假设结果中存在不可转换的值,则以下语句也会失败:
SELECT CONVERT(varchar(23), CONVERT(DATETIME, c.OldValue, 101), 21)
FROM ChangeLog c
WHERE c.FieldID IN ( SELECT v.FieldID
FROM ViewFields v
WHERE FieldDataType IN (4,5,6))
令人惊讶的是,select语句确实可以正常工作。 当我现在尝试再次执行更新语句时,它也可以正常工作。 要再次破坏该声明,请执行 DBCC DROPCLEANBUFFERS 。
在我看来,在读取数值之前,应始终首先评估条件。但在这个例子中,这似乎显然不是这种情况。 问题似乎与缓存有关。 执行计划是相同的。
有人可以解释这里发生了什么吗?
可能的解决方案是使用游标更新值,但在我看来,这不是一个干净的解决方案。
答案 0 :(得分:1)
显然,答案在于sql server引擎如何处理查询。概念查询处理顺序为:
1. from
2. where
3. group by
4. having
5. select
6. order by
但实际上引擎可以决定改变这种排序。它可以先评估select
子句,然后从where
子句应用过滤器。这取决于许多因素。所以实际上这就是你的情况。
解决方法是首先将数据选择到临时表中,然后将强制转换应用于临时表中的数据。
答案 1 :(得分:0)
将日期时间转换为varchar时,无需指定样式参数。
考虑这个CONVERT(varchar(23), CONVERT(DATETIME, c.OldValue, 101), 21)
与此CONVERT(varchar(23), CONVERT(DATETIME, c.OldValue, 101))