2011-01-25 56 views
1

我有一個暫存區域,我試圖驗證數據,經過多次驗證迭代。目前,我正在嘗試將nvarchar(50)列轉換爲日期。TSQL日期轉換失敗 - 我無法理解結果集

我知道形成不良的字符串日期轉換失敗的常見錯誤,所以這就是我正在做的。

SELECT * 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) 
WHERE CAST(DATE_COL AS DATE) < GETDATE() 

...這會導致標準的「從字符串轉換日期和/或時間時轉換失敗」。

但是,這裏的東西變得怪異的我。如果我改變上述聲明如下:

SELECT CAST(DATE_COL AS DATE) 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) 

...一切都很好,而我所做的就是移動從where子句select子句中投。我認爲我在基礎層面上失去了一些東西。

FWIW,如果我從STAGE_TABLE中提取所有記錄而沒有WHERE ISDATE子句,那麼我的日期字符串就會很差。

任何見解非常感謝!

回答

3

您應該發現第一個查詢將兩個WHERE子句合併爲一個,並在ISDATE(失敗)之前計算出CAST。

第二屆查詢顯然必須首先處理WHERE,所以CAST永遠看不到壞的數據

我剛纔測試可以驗證:

create table STAGE_TABLE (date_col nvarchar(50)) 
insert into STAGE_TABLE select 'a' 
insert into STAGE_TABLE select '20100101' 

首先查詢

SELECT * 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) X 
WHERE CAST(DATE_COL AS DATE) < GETDATE() 

第一個計劃

|--Filter(WHERE:(isdate([tempdb].[dbo].[STAGE_TABLE].[date_col])=(1))) 
     |--Table Scan(OBJECT:([tempdb].[dbo].[STAGE_TABLE]), WHERE:(CONVERT(date,[tempdb].[dbo].[STAGE_TABLE].[date_col],0)<getdate())) 

第二個查詢

SELECT CAST(DATE_COL AS DATE) 
    FROM (SELECT * FROM STAGE_TABLE WHERE ISDATE(DATE_COL) = 1) X 

第二個計劃

|--Compute Scalar(DEFINE:([Expr1004]=CONVERT(date,[tempdb].[dbo].[STAGE_TABLE].[date_col],0))) 
     |--Filter(WHERE:(isdate([tempdb].[dbo].[STAGE_TABLE].[date_col])=(1))) 
      |--Table Scan(OBJECT:([tempdb].[dbo].[STAGE_TABLE])) 

似乎沒有成爲一個提示/選項來解決第一個查詢(因爲它被集於一身WHERE子句中),但你可以使用這在一次掃描過程中處理兩個條件。

SELECT * 
    FROM (SELECT * FROM STAGE_TABLE) X 
WHERE CAST(CASE WHEN ISDATE(DATE_COL) = 1 THEN DATE_COL ELSE NULL END AS DATE) < GETDATE() 
+0

太棒了!我仍然是如此薄弱的查詢計劃...... :(所以我假設我應該能夠添加一個提示,強制dbe充分評估內部選擇第一權利?如果是這樣 - 任何意見,我怎麼能做到這一點? – 2011-01-25 01:45:56