我在验证存储过程中有一个查询。它是这样的:
SELECT *
FROM Table1
WHERE batchID IN (SELECT id FROM #tempIds)
AND CAST(field1 AS DATE) > CAST(field2 AS DATE)
field1
和field2
都有有效日期,即在field1 / 2上执行IdDate会返回1.
#tempIds
表只有一列ID
,只包含一行。
当我运行上述查询时,我收到此错误:
无法将varchar转换为日期
但是,如果我从同一个临时表中放入硬编码的ID,它不会从临时表中选择批处理ID。
任何想法可能是什么问题?
答案 0 :(得分:2)
问题是您使用varchar
来存储date
(或datetime
)个值。
为列选择正确的数据类型可以避免许多问题,包括这个问题。有关详细信息,请阅读Aaron Bertrand的Bad habits to kick : choosing the wrong data type。
现在,要在评论中解决我们的对话 - SQL Server不保证评估where子句中条件的顺序。这意味着即使所有"日期& #34;您的列中的字符串都可以转换为特定batchID
的日期值,您只需要在其中一列中输入一个错误的值来提升"无法将varchar
转换为日期"错误。
这也意味着即使你在哪里写你的查询,拉里B在他的回答中建议的方式(现在删除 - 所以为了未来的读者 - 这是他的建议:)
SELECT *
FROM Table1
WHERE batchID IN (SELECT id FROM #tempIds)
AND ISDATE(field1) = 1
AND ISDATE(field2) = 1
AND CAST(field1 AS DATE) > CAST(field2 AS DATE)
无法保证最后一个条件(cast(field1 as date) > cast(field2 as date)
)会在<{strong> isdate(field1)=1
条件后进行评估。
正确的做法是解决问题 - 将列的数据类型更改为正确的数据类型。
假设无法完成(例如,如果您无法控制数据库的结构) - 您可以做以下几件事:
找到field1
和field2
中的值无法转换为日期并修复它们的所有位置。考虑添加一个检查约束来验证这些列的值是否可以转换为日期(假设您可以)。
将您的查询分为两部分:
;With cte as
(
SELECT *
FROM Table1
WHERE batchID IN (SELECT id FROM #tempIds)
AND ISDATE(field1) = 1
AND ISDATE(field2) = 1
)
SELECT *
FROM cte
WHERE CAST(field1 AS DATE) > CAST(field2 AS DATE)
这将消除错误,因为您只是在ISDATE
函数已经返回1的情况下转换值,但如果值为field1
或{{{},则可能不返回您要返回的某些行1}}这些行是错误的。