我想我總是天真地認爲SQL查詢的選擇部分中的標量函數將只適用於滿足where子句的所有條件的行。執行SQL語句時可以在過濾之前應用標量函數嗎?
今天我正在調試供應商的一些代碼,並有這個假設的挑戰。我能想到的代碼失敗的唯一原因是Substring()函數正在調用應該被WHERE子句過濾掉的數據。但是,似乎在過濾發生之前正在應用子串調用,查詢失敗。 這裏是我的意思的例子。假設我們有兩個表格,每個表格有2列,分別有2行和1行。每個中的第一列只是一個id。 NAME只是一個字符串,NAME_LENGTH告訴我們名稱中有多少個字符具有相同的ID。請注意,只有具有多個字符的名稱在LONG_NAMES表中具有對應的行。
NAMES: ID, NAME
1, "Peter"
2, "X"
LONG_NAMES: ID, NAME_LENGTH
1, 5
如果我想查詢打印每名以切斷最後3個字母,我可能會先嚐試這樣的事情(假設SQL Server語法現在):
SELECT substring(NAME,1,len(NAME)-3)
FROM NAMES;
我很快會發現這會給我一個錯誤,因爲當它到達「X」時,它會嘗試在子串調用中使用負數,並且它會失敗。 我的供應商決定解決這個問題的方式是過濾掉那些字符串太短而無法使len - 3查詢正常工作的行。他通過加入另一個表來完成它:
SELECT substring(NAMES.NAME,1,len(NAMES.NAME)-3)
FROM NAMES
INNER JOIN LONG_NAMES
ON NAMES.ID = LONG_NAMES.ID;
乍一看,這個查詢看起來像可能工作。連接條件將消除任何具有足夠短的NAME字段的行,以使子字符串調用失敗。
但是,從我可以觀察到的情況來看,SQL Server有時會嘗試計算表中所有內容的子字符串表達式,然後應用聯接來過濾掉行。這是否應該以這種方式發生?是否有一個記錄的操作順序,我可以找出什麼時候會發生某些事情?它是特定於某個特定的數據庫引擎還是SQL標準的一部分?如果我決定在我的NAMES表中包含一些謂詞來過濾短名稱(如len(NAME)> 3),SQL Server是否也可以在嘗試應用子字符串後選擇應用該謂詞?如果是這樣,那麼似乎做一個子字符串的唯一安全方法是將其包裝在select中的「case when」構造中?
是的。 'CASE'是這樣做的唯一安全方式。請參閱http://stackoverflow.com/questions/5191701/tsql-divide-by-zero-encountered-despite-no-columns-containing-0/5203211#5203211以獲得有關此主題的良好答案。 – 2011-03-09 17:40:34
@Martin感謝您的鏈接。我無法弄清楚如何搜索類似的問題,因爲它是抽象的。 – 2011-03-09 17:46:34