SQL Server中,WITH AS的使用
一.WITH AS的含義
WITHAS短語,也叫做子查詢部分(subqueryfactoring),定義一個SQL片斷,該SQL片斷會被整個SQL語句所
用到。有的時候,是為了讓SQL語句的可讀性更高些,也有可能是在UNIONALL的不同部分,作為提供資料的部分。特
別對於UNIONALL比較有用。因為UNION ALL的每個部分可能相同,但是如果每個部分都去執行一遍的話,則成本太
高,所以可以使用WITHAS短語,則只要執行一遍即可。如果WITH AS短語所定義的表名被呼叫兩次以上,則優化器會
自動將WITHAS短語所獲取的資料放入一個TEMP表裡,如果只是被呼叫一次,則不會。而提示materialize則是強制將
WITHAS短語裡的資料放入一個全域性臨時表裡。很多查詢通過這種方法都可以提高速度。
二.巢狀查詢和表變數查詢
做過報表或者維護過報表的人都知道,報表最讓人噁心的就是屢不清的sql和烏龜一樣的速度。巢狀查詢,尤其
是多重巢狀是最讓人噁心的,前段時間維護一個報表,一百多行的sql,也不知道是那個大神,用一句sql搞定的,各
種巢狀,雖然開發時沒什麼感覺,可是維護人員就徹底暈菜了,根本就找不到那是那,最後沒辦法只能跟組長申請重
新開發吧,沒辦法維護啊,根本就不存在可讀性這一說。還有就是表變數查詢,也就是我們常說的藉助臨時表,這樣
雖然提高了可讀性和維護性,但是增加了額外的I/O開銷,如果資料量大且頻繁查詢時,就會出現烏龜一般的查詢速
度。
資料量小或者查詢次數少的時候這兩種方式沒有什麼問題,但我覺得為了提供效率和方便後面的人員維護,讓後
面維護的人喜歡你開發的報表,我們可以採用CTE(CommonTable Expression) ,即公用表表達式。它提高SQL語句的
可維護性,同時,CTE要比表變數的效率高得多。
三.CTE的語法
<span style="font-size:18px;">[ WITH<common_table_expression> [ ,n ] ] <common_table_expression>::= expression_name [ ( column_name [ ,n ] ) ] AS ( CTE_query_definition )</span>
簡單例項:
<span style="font-size:18px;">withtest_CTE(id,salary)
as
(
select id,max(salary)
from test
group by id
)
select * fromtest_cte</span>
由上面例題可以看出:CTE 由表示 CTE的表示式名稱、可選列列表和定義 CET 的查詢組成。
四.CTE注意事項
1.CTE後面必須直接跟使用CTE的SQL語句(如select、insert、update等),否則,CTE將失效。如下面的SQL語句將
無法正常使用CTE:
<span style="font-size:18px;">with
Test_CTEas
(
select code fromTenement.PropertyProject where CnName like '%大連%'
)
select * fromTenement.PropertyProduct -- 應將這條SQL語句去掉
--使用CTE的SQL語句應緊跟在相關的CTE後面 --
select* from Tenement.PropertyProject where code in (select * from Test_CTE) </span>
2.CTE後面也可以跟其他的CTE,但只能使用一個with,多個CTE中間用逗號(,)分隔,如下面的SQL語句所示:
<span style="font-size:18px;">with
Project as
(
select * from PropertyProject where CnName like '大連%'
),
House as
(
select * from Tenement.PropertyHouse where roomNo > 20
),
Unit as
(
select * from Tenement.[PropertyUnit]where CnName like '%遠洋自然%'
)
selectHouse .* from Project a, Houseb, Unit c where a.code = b.projectCode and a.code = c.projectCode </span>
3.如果CTE的表示式名稱與某個資料表或檢視重名,則緊跟在該CTE後面的SQL語句使用的仍然是CTE,當然,後面的
SQL語句使用的就是資料表或檢視了,如下面的SQL語句所示:
<span style="font-size:18px;">-- Project是一個實際存在的表
with
Project as
(
select * from PropertyProject where CnName like '大連%'
)
select * from Project-- 使用了名為Project 的公共表表達式
select * from Project-- 使用了名為Project 的資料表 </span>
4. CTE可以引用自身,也可以引用在同一 WITH 子句中預先定義的 CTE。不允許前向引用。
5. 不能在CTE_query_definition 中使用以下子句:
(1)COMPUTE 或 COMPUTEBY
(2)ORDER BY(除非指定了 TOP子句)
(3)INTO
(4)帶有查詢提示的 OPTION子句
(5)FOR XML
(6)FOR BROWSE
6. 如果將 CTE用在屬於批處理的一部分的語句中,那麼在它之前的語句必須以分號結尾,如下面的SQL所示:
<span style="font-size:18px;">declare @snvarchar(3)
set @s = '大連%'
; -- 必須加分號
with
Project as
(
select Code from PropertyProject where CnName like @s
)
select * from PropertyProject where Code in (select * fromProject) </span>
五.優點
1.使用 CTE 可以獲得提高可讀性和輕鬆維護複雜查詢的優點。
2.查詢可以分為單獨塊、簡單塊、邏輯生成塊。這些簡單塊可用於生成更復雜的臨時 CTE,直到生成最終結果集。
六.總結:
CTE在一定程度上解決了巢狀查詢帶來的可讀性差以及表變數查詢造成的查詢效率問題,但它不能解決所有的問
題,只能說當資料量大,並且邏輯比較複雜時,CTE比這兩種方式更有優勢。當然這個年底傻傻的寫sql是很可恥的。