2012-11-01 33 views
5

我有這樣一個觀點:WHERE上查看別名導致錯誤

SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode 
FROM dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 

如果我這樣稱呼它,它的工作原理:

SELECT * FROM FooView 

但是,如果我添加一個WHERE子句:

SELECT * FROM FooView WHERE ProcessCode > 0 

我得到這個錯誤:

Conversion failed when converting the varchar value '-01-' to data type int.

爲什麼?由於位置必須採用1-2-100-0800-A的格式,因此我看不到可能存在轉換錯誤。在WHERE有機會過濾結果之前CAST可能失敗嗎?如果是這樣,那麼爲什麼第一個查詢工作?

編輯 - 變通

我剛做了一個同事提出一個很好的變通。它的工作原理,但它仍不能解釋爲什麼最初的問題。

這是SELECT的ProcessCode:在哪裏之前

CASE WHEN location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_' 
THEN CAST(SUBSTRING(location, 9, 4) AS int) ELSE 0 END AS ProcessCode, 
+0

出於興趣哪個版本的sql server?以及什麼列類型是位置? –

+0

SQL Server 2012.位置是varchar(24)。 –

回答

4

將您的看法改爲這個

SELECT location, 
     CASE WHEN SUBSTRING(location, 9, 4) > '' 
      AND SUBSTRING(location, 9, 4) NOT LIKE '%[^0-9]%' THEN 
       CAST(SUBSTRING(location, 9, 4) AS int) END AS ProcessCode 
    FROM dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
    AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 

看到這個Connect item

SQL Server是免費的,因爲它決定被優化以評估WHERE/SELECT子句。除非實現爲INDEXED VIEW,否則視圖擴展到外部查詢,因此您的WHERE子句實際上正在流線化到視圖中,即

SELECT * FROM FooView WHERE ProcessCode > 0 
-- is really seen as 
SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode 
FROM dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 
AND CAST(SUBSTRING(location, 9, 4) AS int) > 0 ---- << Expanded inline 

因爲表達既被用於SELECT和WHERE子句,似乎SQL Server已決定先解決原有檢索SELECT子句中的表達。通過使用Ctrl-L查看查詢執行計劃可以很容易地看到這一點。您將看到SQL Server從表格中進行單個檢索,同時獲取2個表達式,分別爲locationCAST(SUBSTRING(location, 9, 4) AS int)

+0

謝謝。這有點像我的問題中的解決方法。看我的編輯。雖然它提供了一個可行的選擇,但它並不能解釋原來的行爲。 –

+0

我已經添加了一個解釋。此外,您的解決方法有點依賴於數據,因爲您不是在測試正在播放的位,而是在測試列數據的模式。 – RichardTheKiwi

+0

這將解釋行爲。如果在WHERE有機會過濾不良數據之前對SELECT進行評估,則會導致錯誤。那是你在說什麼? –

0

轉換失敗,是的。事實上,如果我沒有弄錯,在它看到表格並確定位置列下的子字符串的形狀之後,演員表在SELECT本身之前失敗。

您似乎在對返回的子字符串進行錯誤計算,因爲如果您說的格式確實是1-2-100-0800-A,則SUBSTRING(str,9,4)應返回0800 ,但它返回'-1-',這不是一個INT。

將您的陳述剖析爲較小的陳述。我會首先研究SUBSTRING的結果。

希望有所幫助。

+1

謝謝,但我不認爲我錯誤地計算了Substring返回的結果。我認爲整個問題是演員陣容在WHERE過濾器之前發生,但我可能是錯的。如果是這樣的話,那麼爲什麼第一個查詢會起作用呢? –

1

這工作SQL Server 2008中,別的時髦是怎麼回事...上

create view myview 
AS 
SELECT CAST(SUBSTRING('1-2-100-0800-A', 9, 4) AS int) as ProcessCode 
Where '1-2-100-0800-A' LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_' 

GO 

SELECT * FROM myview WHERE ProcessCode > 0 

這裏的小提琴>http://sqlfiddle.com/#!3/3bcfd/2

編輯可能是執行的順序如下建議,嘗試它帶有一個in(使用ID進行優化)

SELECT location, CAST(SUBSTRING(location, 9, 4) AS int) AS ProcessCode 
FROM dbo.asset 
Where id in(
select id 
from dbo.asset 
WHERE (status NOT IN ('INACTIVE', 'NOT READY', 'LIMITEDUSE')) 
AND (location LIKE '[1-6]-[12]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-_') 
) 
+0

我認爲這是有效的,因爲你只用一個測試,價值很高。還有其他的不好的值應該通過WHERE子句去除。 –

+0

你能給出一個「壞」值的例子嗎? –

+0

當然,任何不符合常規表達的東西:ALM00-00-06,1-5-RMT,1-0-DEV。 –