2013-06-18 107 views
0

我有以下的SQL查詢有一個交叉應用子查詢。SQL查詢與CROSS APPLY拋出錯誤

SELECT 
    pm.[FileName] 
    ,REPLACE([Message], 'Upload End. Total Row:', '') cnt_char 
    ,CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT) AS row_count 
FROM 
    dbo.ProductMaster pm 
CROSS APPLY 
    (SELECT TOP 30 * 
    FROM dbo.ActivityLog lo 
    WHERE [Message] like 'Upload End%' 
     AND lo.[FileName] = pm.[FileName] 
    ORDER BY ActivityDate DESC) AS s 

它運行正常,但如果我刪除第二個表達式(,REPLACE([Message], 'Upload End. Total Row:', '') cnt_char)的選擇,我得到以下錯誤

消息245,級別16,狀態1,行
轉換失敗當將varchar值'Upload Start'轉換爲數據類型int時。

子查詢中的where子句應特別排除Message是「Upload Start」的所有行,但爲什麼會出現此錯誤。我沒有正確使用CROSS APPLY嗎?

回答

1

SQL是一種描述性的語言,而不是程序語言。 cross apply的方法在邏輯上解釋瞭如何生成結果。他們沒有指定執行計劃。查詢優化器可以自由選擇任何生成正確結果集的查詢計劃。

您需要查看兩個查詢的執行計劃。我的猜測是他們在根本上有所不同。在處理類型轉換時,不應依賴where子句來篩選之前的的轉換。相反,你應該使用case。您的外部查詢應該如下所示:

(case when [Message] like 'Upload End. Total Row:%' 
     then CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT) 
     when isnumeric([Message]) = 1 
     then cast([Message] as int) 
end) as row_count; 
1

SQL Server可以以任意順序執行查詢。這意味着它可以選擇所有行,並且以後只應用過濾器。允許以任何方式來保證達到相同的結果。

不幸的是,該保證只涉及關係邏輯,而不是鑄造操作員。

一條出路是雙重檢查:

case when Message like 'Upload End.%' then 
    CAST(REPLACE([Message], 'Upload End. Total Row:', '') AS INT) 
else null 
end AS row_count 
+0

您的答案與我接受的答案相同,但因爲另一個解釋它更好,所以接受該答案。我贊成你。謝謝。 – Satish