典型的回答是添加一個WHERE子句:
WHERE ISDATE(a.valor) = 1
然而,這是一對夫婦的原因,您的情況有問題:
ISDATE()
不一定會符合你的方式希望取決於服務器的區域設置,用戶的語言或日期格式選項等。例如:
SET DATEFORMAT dmy;
SELECT ISDATE('13/01/2012'); -- 1
SET DATEFORMAT mdy;
SELECT ISDATE('13/01/2012'); -- 0
您無法真正控制該SQL Server將嘗試並在篩選器後執行CONVERT
。
你甚至不能使用子查詢或CTE的嘗試和過濾器從CONVERT分開,因爲SQL Server 可以在任何順序它認爲更有效的查詢優化操作。
例如,用有限的樣本,你可能會發現,這個工作好:
SET DATEFORMAT dmy;
SELECT valor, valor_date FROM (
SELECT valor, valor_date = CONVERT(DATE,
CASE WHEN ISDATE(valor) = 1 THEN valor ELSE NULL END, 103)
FROM dbo.mytable
WHERE ISDATE(valor) = 1
) AS sub WHERE valor_date BETWEEN '01/01/2012' AND '01/03/2012';
但我已經看到了其中的SQL Server試圖先評估過濾器,即使這個結構的情況下,導致你目前得到的錯誤。
幾個更安全的解決方法:
添加計算列,例如
ALTER TABLE dbo.mytable ADD valor_date
AS CONVERT(DATE, CASE WHEN ISDATE(valor) = 1 THEN valor
ELSE NULL END, 103);
爲了防止您在運行時出現可能的錯誤解釋,您應該在發出引用計算列的查詢之前指定dateformat,例如,
SET DATEFORMAT dmy;
SELECT valor, valor_date FROM dbo.mytable WHERE ...;
創建一個視圖:
CREATE VIEW dbo.myview
AS
SELECT valor, valor_date = CONVERT(DATE,
CASE WHEN ISDATE(valor) = 1 THEN valor ELSE NULL END, 103)
FROM dbo.mytable
WHERE ISDATE(valor) = 1;
同樣,你想查詢視圖時發出SET DATEFORMAT
。
使用臨時表:
SELECT <cols>
INTO #foo
FROM dbo.mytable
WHERE ISDATE(valor) = 1;
SELECT <cols>, CONVERT(DATE, valor) FROM #foo WHERE ...;
您可能仍然希望使用DATEFORMAT
保護自己免受ISDATE
和用戶設置之間的衝突。
不,你應該不嘗試驗證自己的字符串作爲使用字符串模式匹配日期爲另一個(現已刪除)回答與會者提出:
like '%__/%' or like '%/%'
你必須有一些非常複雜和嚴格的驗證來處理所有有效的日期,包括閏年。
需要首先執行不包括日期的查詢,然後對日期執行第二個查詢,最後將這兩個數據集綁定在一起? –