使用公用表表達式(CTE)簡化嵌套SQL

字號:

先看下面一個嵌套的查詢語句:
    select*fromperson.StateProvincewhereCountryRegionCodein
    (selectCountryRegionCodefromperson.CountryRegionwhereNamelike’C%’)
    上面的查詢語句使用了一個子查詢。雖然這條SQL語句并不復雜,但如果嵌套的層次過多,會使SQL語句非常難以閱讀和維護。因此,也可以使用表變量的方式來解決這個問題,SQL語句如下:
    declare@ttable(CountryRegionCodenvarchar(3))
    insertinto@t(CountryRegionCode) (selectCountryRegionCodefromperson.CountryRegionwhereNamelike’C%’)
    select*fromperson.StateProvincewhereCountryRegionCode
    in(select*from@t)
    雖然上面的SQL語句要比第一種方式更復雜,但卻將子查詢放在了表變量@t中,這樣做將使SQL語句更容易維護,考試大提示會帶來另一個問題,就是性能的損失。由于表變量實際上使用了臨時表,從而增加了額外的I/O開銷,因此,表變量的方式并不太適合數(shù)據(jù)量大且頻繁查詢的情況。為此,在SQL Server 2005中提供了另外一種解決方案,這就是公用表表達式(CTE),使用CTE,可以使SQL語句的可維護性,同時,CTE要比表變量的效率高得多。
    下面是CTE的語法:
    [ WITH [ ,n ] ]
    ::=
    expression_name [ ( column_name [ ,n ] ) ]
    AS
    ( CTE_query_definition )
    現(xiàn)在使用CTE來解決上面的問題,SQL語句如下:
    with
    cras
    (
    selectCountryRegionCodefromperson.CountryRegionwhereNamelike’C%’
    )
    select*fromperson.StateProvincewhereCountryRegionCodein(select*fromcr)
    其中cr是一個公用表表達式,該表達式在使用上與表變量類似,只是SQL Server 2005在處理公用表表達式的方式上有所不同。
    在使用CTE時應注意如下幾點:
    1.CTE后面必須直接跟使用CTE的SQL語句(如select、insert、update等),否則,CTE將失效。如下面的SQL語句將無法正常使用CTE:
    with
    cras
    (
    selectCountryRegionCodefromperson.CountryRegionwhereNamelike’C%’
    )
    select*fromperson.CountryRegion --應將這條SQL語句去掉
    --使用CTE的SQL語句應緊跟在相關的CTE后面--
    select*fromperson.StateProvincewhereCountryRegionCodein(select*fromcr)
    2.CTE后面也可以跟其他的CTE,但只能使用一個with,多個CTE中間用逗號(,)分隔,如下面的SQL語句所示:
    with
    cte1as
    (
    select*fromtable1wherenamelike’abc%’
    ),
    cte2as
    (
    select*fromtable2whereid>20
    ),
    cte3as
    (
    select*fromtable3whereprice<100
    )
    selecta.*fromcte1a,cte2b,cte3cwherea.id=b.idanda.id=c.id
    3.如果CTE的表達式名稱與某個數(shù)據(jù)表或視圖重名,則緊跟在該CTE后面的SQL語句使用的仍然是CTE,當然,后面的SQL語句使用的就是數(shù)據(jù)表或視圖了,如下面的SQL語句所示:
    -- table1是一個實際存在的表
    with
    table1as
    (
    select*frompersonswhereage<30
    )
    select*fromtable1 -- 使用了名為table1的公共表表達式
    select*fromtable1 -- 使用了名為table1的數(shù)據(jù)表
    4.CTE 可以引用自身,也可以引用在同一 WITH 子句中預先定義的 CTE。不允許前向引用。
    5.不能在 CTE_query_definition 中使用以下子句:
    (1)COMPUTE 或 COMPUTE BY
    (2)ORDER BY(除非指定了 子句)
    (3)INTO
    (4)帶有查詢提示的 OPTION 子句
    (5)FOR XML
    (6)FOR BROWSE
    6.如果將 CTE 用在屬于批處理的一部分的語句中,那么在它之前的語句必須以分號結尾,如下面的SQL所示:
    declare@snvarchar(3)
    set@s=’C%’
    ; --必須加分號
    with
    t_treeas
    (
    selectCountryRegionCodefromperson.CountryRegionwhereNamelike@s
    )
    select*fromperson.StateProvincewhereCountryRegionCodein(select*fromt_tree)
    CTE除了可以簡化嵌套SQL語句外,還可以進行遞歸調(diào)用,關于這一部分的內(nèi)容將在下一篇文章中介紹。