スタック オーバーフローに関する別の 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';