在尝试回答有关 Stack Overflow 的另一个 SQL Server 问题时,我遇到了一些无法按预期工作的问题。我使用的是 SQL Server 2008R2,但这可能并不重要。
我有一个简单的假设表,其中一些日期存储为 VARCHAR 数据类型。我知道使用 DATE 数据类型存储日期信息是显而易见且实用的,但此示例有意使用 VARCHAR 来演示我遇到的问题。日期无效的原因并不重要——可能是清理不当、更新查询格式错误、发挥您的想象力等。
-- setup
CREATE TABLE #temp (DateString VARCHAR(10));
INSERT #temp (DateString) VALUES ('01/01/2013');
INSERT #temp (DateString) VALUES ('02/14/2013');
INSERT #temp (DateString) VALUES ('03/31/2013');
INSERT #temp (DateString) VALUES ('05/27/2013');
INSERT #temp (DateString) VALUES ('06/31/201'); -- known invalid date, maybe the data wasn't sanitized, etc.
INSERT #temp (DateString) VALUES ('07/04/2013');
我想选择 2013 年 7 月 1 日之前的假期数。我怀疑日期可能无效,所以我必须为此做好计划以避免异常。在我编写以下这些查询之前,我知道它们会失败:
-- fails: cast exception, obviously
SELECT COUNT(*) AS [CountHolidays]
FROM #temp
WHERE CAST(DateString AS DATE)<'20130701';
-- fails: ISDATE() is not gauranteed to be evaluated first, less obvious, pointed out by another user.
SELECT COUNT(*) AS [CountHolidays]
FROM #temp
WHERE ISDATE(DateString) = 1 AND CAST(DateString AS DATE)<'20130701';
此查询按预期工作,将是我的最终选择:
-- works
SELECT COUNT(*) AS [CountHolidays]
FROM #temp
WHERE CONVERT(DATE,CASE WHEN ISDATE(DateString)=1 THEN datestring ELSE NULL END) < '20130701';
不过,在我编写最终查询之前,我先尝试了这个,我希望它能够工作,但它也会引发一个强制转换异常。为什么这个查询特别失败?
-- Why does this query fail specifically?
-- I expected my derived inner query to filter invalid dates out first, but it does not. I get the same cast exception.
SELECT COUNT(*) AS [CountHolidays]
FROM (
-- the derived table returns expected data when executed independently.
SELECT DateString
FROM #temp
WHERE ISDATE(DateString) = 1
) AS T
WHERE CAST(DateString AS DATE)<'20130701';