2015-11-15 117 views
0

這裏是我的查詢:SQL Server的日期轉換錯誤

SELECT 
    * 
FROM 
    (SELECT 
     A.Name, AP.PropertyName, APV.Value AS [PropertyValue], 
     CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue] 
    FROM dbo.Account AS A 
    JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId 
    JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId 
              AND APV.AccountId = A.AccountId 
    WHERE 
     A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR 
     AND AP.PropertyName LIKE '%DATE%' 
     AND ISDATE(APV.Value) = 1 
     AND LEN(SUBSTRING(REVERSE(APV.Value), 0 , CHARINDEX('/',  REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year 
    ) AS APV 
WHERE 
    APV.DateValue < GETDATE() 

這將導致以下錯誤:

Conversion failed when converting date and/or time from character string.

如果您註釋掉WHERE APV.DateValue < GETDATE()條款則沒有錯誤,我得到的300多行。當我啓用WHERE子句時,出現錯誤。

因此,你要告訴我我的數據是正確的嗎?那是我的想法,所以我試圖找出數據中的問題所在,所以我開始使用TOP()來隔離位置。問題一旦我使用TOP()函數錯誤消失,我只有2000行數據開始。所以我在內部SELECT上放了一個荒謬的TOP(99999999),現在整個查詢都起作用了。

內部SELECT返回相同的行數(有或沒有TOP())。

爲什麼?

僅供參考,這是SQL的作品:

SELECT 
    * 
FROM 
    (SELECT TOP(99999999) 
     A.Name, AP.PropertyName, APV.Value AS [PropertyValue], 
     CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue] 
    FROM dbo.Account AS A 
    JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId 
    JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId 
              AND APV.AccountId = A.AccountId 
    WHERE 
     A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR 
     AND AP.PropertyName LIKE '%DATE%' 
     AND ISDATE(APV.Value) = 1 
     AND LEN(SUBSTRING(REVERSE(APV.Value), 0 , CHARINDEX('/',  REVERSE(APV.Value)))) = 4 
    ) AS APV 
WHERE 
    APV.DateValue < GETDATE() 
+0

反對?很確定問題很清楚,有例子嗎?匿名投票的結果究竟是什麼? –

+0

我看不到'WHERE APV.DateValue

+0

我改變了我的地方...對不起,這是測試代碼...將更新帖子。 –

回答

0

我的猜測是,你的日期是這樣的:APV.VALUE還包含不能轉換成日期數據,因此應該用其他標準來過濾掉?

由於SQL Server可以決定限制首先使用您已經給出了標準的數據:

APV.DateValue < CONVERT(DATETIME, GETDATE(),101) 

,如果有無法轉換成日期數據,那麼你會得到錯誤。

爲了使它更清楚,這是被過濾的內容:

CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue] 

,如果有不能被轉換成使用101格式的日期的任何數據,使用GETDATE過濾器()將失敗,即使該行不會包含在最終結果集中,例如因爲AP.PropertyName不包含DATE

由於您使用SQL Server 2012中,使用try_convert而不是轉換應該解決您的問題

,爲什麼它與頂級的作品?在這種情況下,SQL Server不能使用外部查詢中的條件,因爲結果可能會發生變化,因爲它可能會影響頂部返回的行數

+0

並非如此。閱讀我的整篇文章,內部選擇返回EXACT相同的行數(有或沒有TOP)... –

+0

Top影響查詢計劃,因爲過濾器無法在頂部的另一側移動。也比答案中增加了。 –

+0

然後它沒有TOP失敗,因爲????? –

0

您面臨的問題是SQL Server可以評估表達式在查詢處理過程中的任何時候 - 甚至在WHERE子句被評估之前。這對性能可能是一大好處。但是,結果是錯誤可能由不在最終結果集中的行生成。 (除零以及轉換錯誤都是如此。)

幸運的是,SQL Server解決了轉換問題。使用try_convert()

TRY_CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue] 

如果出現問題,將返回NULL而不是錯誤。

某些版本工作而其他人不工作的原因是因爲執行順序。實際上沒有辦法預測什麼可行,哪些不行 - 如果查詢的執行計劃出於其他原因(如表統計)發生更改,它可能會發生變化。因此,請使用try_convert()

+0

什麼版本的SQL服務器有TRY_CONVERT()? –

+0

我收到一個錯誤。 –

+0

@ TMcKeown。 。 。 SQL Server 2012+(這就是爲什麼我建議它):ft.com/en-us/library/hh230993(v=sql.110).aspx。 –

0

由於表中的記錄數< 999..99。關於這個錯誤,看起來像SQL引擎在轉換到日期之後評估WHERE子句,所以你可以試試這個:

SELECT * 
FROM (
SELECT A.Name 
    , AP.PropertyName 
    , APV.Value AS [PropertyValue] 
    , 
    CASE 
    WHEN SDATE(APV.Value) = 1 
    THEN CONVERT(DATETIME, APV.VALUE, 101) 
    ELSE NULL 
    END AS [DateValue] 
FROM dbo.Account AS A 
JOIN dbo.AccountProperty AS AP 
    ON AP.AccountTypeId = A.AccountTypeId 
JOIN dbo.AccountPropertyValue AS APV 
    ON APV.AccountPropertyId = APV.AccountPropertyId 
    AND APV.AccountId = A.AccountId 
WHERE A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR 
    AND AP.PropertyName LIKE '%DATE%' 
    AND LEN(SUBSTRING(REVERSE(APV.Value), 0 , CHARINDEX('/',  REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year 
    ) AS APV 
WHERE APV.DateValue IS NOT NULL AND APV.DateValue < GETDATE() 
+0

我不認爲它與行數有關,而是因爲SQL Server無法將外部查詢中的where子句移動到內部(如果存在top),因爲它可能會更改結果。 –

+0

這種錯誤可以在try_convert不可用時處理(2012年之前),但如果可能的話,我建議使用try_convert,因爲它更容易理解它的作用。 –