1. 程式人生 > >T-SQL All-At-Once 操作解析

T-SQL All-At-Once 操作解析

wid 就會 例子 strong 是否 一個 adding sqlserver san

SQL支持一種所謂的同時操作的概念,其含義是認為在同一邏輯查詢處理階段中出現的所有表達式都是同時進行計算的。例如,這個概念就可以解釋為什麽不能在SELECT子句中引用為同一SELECT子句中的列分配的別名,即使直覺上看起來應該能夠這麽做。考慮以下查詢:

SELECT 
    orderid,
    YEAR(orderdate) AS orderyear, 
    orderyear + 1 AS nextyear 
FROM Sales.Orders; 

以上SELECT列表中第三個表達式對orderyear這一列別名的引用是無效的,即使引用表達式位於這個別名的定義”之後”。因為從邏輯上來說,SELECT列表中各表達式的計算是沒有順序的——它們只是一組表達式。在邏輯上SELECT列表中的所有表達式都
是在同一時刻進行計算的。

再舉—個例子:假設你有一個稱為T1的表,它有兩個整數列:coll 和col2。現在想返回col2/coll大於2的所有行。因為表中一些行的coll列可能等於0,所以需要確保不能對這些列執行除法運算,否則,查詢會因為除數為0的錯誤而失敗。為此,有以下查詢語句:

SELECT coll, col2 
FROM dbo.Tl 
WHERE col1<> 0 AND col2/col1 > 2; 

這條語句假設SQLServer按從左到右的順序來計算各表達式,如果表達式col1<>0的結果為FALSE,SQL Server 將會按照“短路求值”的原則,停止計算這個表達式:也就是說,它不會再多此一舉地計算表達式col2/col1 > 2, 因為這時已經知道整
個表達式的結果為FALSE。所以可能認為這個查詢應該絕不會發生除數為0的錯誤,然而並不是。

SQL Server確實支待“短路求值”,但因為ANSI SQL中有“同時操作“這麽個概念,所以SQL Server可以按它喜歡的任意順序來自由地處理WHERE子句中的表達式。對於這類問題,SQLServer通常是基於代價估計的標準來做出決定的,也就是說,通常是先計算需要付出較小代價的表達式。可以看到,如果SQLServer決定先處理表達式col2/col1 > 2, 那麽該查詢可能會因為除數為0的錯誤而失敗。

為了盡可能避免查詢執行失敗,此處可以采用幾種方法。例如,CASE表達式中的 WHEN 子句的計算順序是有保障的。所以,可以將上面的查詢修改如下:

SELECT coll, col2 
FROM dbo.T1 WHERE E CASE WHEN col1= 0 THENno WHEN col2/col1 > 2 THENyes ELSEno END =yes;

如果某個行的col1列等於0,第一個WHEN子句的計算結果就為TRUE,CASE表達式就會返回字符串‘no‘(如果當col1等於0時返回該行,可以將no‘換為‘yes‘)。只有當第一個CASE表達式的計算結果不等千TRUE(即coll不為0),第二個WHEN子句才會檢查表達式col2/col1> 2的結果是否為TRUE。如果為TRUE,CASE表達式則返回字符串‘yes‘。對於其他所有情況,CASE表達式將返回字符串‘no‘。只有當CASE表達式的計算結果等於字符串‘yes‘時,WHERE子句中的謂詞才會返回TRUE。這樣,在表達式中就肯定不會出現除數為0的錯誤了。

這種解決辦法實際上顯得很哆嗦,在這個特定的例子中,我們可以使用一種更簡單的數學辦法來避免除數為0的錯誤:

SELECT coll, col2 
FROM dbo.Tl 
WHERE coll<> 0 and col2 > 2*col1 ; 

示例代碼解釋了“同時操作“這一SQL獨特而又重要的概念,以及SQLServer 可以確保CASE表達式中WHEN子句的處理順序這一事實。

 

好了,本篇文章就介紹到這兒,歡迎大家留言交流;喜歡或有幫助到您的話,點個贊或推薦支持一下! 

T-SQL All-At-Once 操作解析