<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
    數(shù)據(jù)加載中……

    SQL Server2005雜談(2):公用表表達式(CTE)的遞歸調(diào)用

    本文為原創(chuàng),如需轉(zhuǎn)載,請注明作者和出處,謝謝!

    上一篇:SQL Server2005雜談(1):使用公用表表達式(CTE)簡化嵌套SQL

    先看如下一個數(shù)據(jù)表(t_tree):

        上圖顯示了一個表中的數(shù)據(jù),這個表有三個字段:idnode_nameparent_id。實際上,這個表中保存了一個樹型結(jié)構(gòu),分三層:省、市、區(qū)。其中id表示當(dāng)前省、市或區(qū)的id號、node_name表示名稱、parent_id表示節(jié)點的父節(jié)點的id
        現(xiàn)在有一個需求,要查詢出某個省下面的所有市和區(qū)(查詢結(jié)果包含省)。如果只使用SQL語句來實現(xiàn),需要使用到游標(biāo)、臨時表等技術(shù)。但在SQL Server2005中還可以使用CTE來實現(xiàn)。

        從這個需求來看屬于遞歸調(diào)用,也就是說先查出滿足調(diào)價的省的記錄,在本例子中的要查“遼寧省”的記錄,如下:

    id   node_name   parent_id

    1     遼寧省        0

        然后再查所有parent_id字段值為1的記錄,如下:

    id   node_name   parent_id

    2      沈陽市       1

    3      大連市       1

        最后再查parent_id字段值為23的記錄,如下:

    id    node_name    parent_id

    4       大東區(qū)        2

    5       沈河區(qū)        2

    6       鐵西區(qū)        2

        將上面三個結(jié)果集合并起來就是最終結(jié)果集。

        上述的查詢過程也可以按遞歸的過程進行理解,即先查指定的省的記錄(遼寧省),得到這條記錄后,就有了相應(yīng)的id值,然后就進入了的遞歸過程,如下圖所示。

        從上面可以看出,遞歸的過程就是使用union all合并查詢結(jié)果集的過程,也就是相當(dāng)于下面的遞歸公式:

        resultset(n) = resultset(n-1) union all current_resultset

        其中resultset(n)表示最終的結(jié)果集,resultset(n - 1)表示倒數(shù)第二個結(jié)果集,current_resultset表示當(dāng)前查出來的結(jié)果集,而最開始查詢出“遼寧省”的記錄集相當(dāng)于遞歸的初始條件。而遞歸的結(jié)束條件是current_resultset為空。下面是這個遞歸過程的偽代碼:

     

    public resultset getResultSet(resultset)
    {
        
    if(resultset is null)
        {
            current_resultset 
    =第一個結(jié)果集(包含省的記錄集)
            將結(jié)果集的id保存在集合中
            getResultSet(current_resultset)
        }
        current_resultset 
    = 根據(jù)id集合中的id值查出當(dāng)前結(jié)果集
        
    if(current_result is nullreturn resultset
        將當(dāng)前結(jié)果集的id保存在集合中
        
    return  getResultSet(resultset union all current_resultset)
    }

    // 獲得最終結(jié)果集
    resultset 
    = getResultSet(null)

        從上面的過程可以看出,這一遞歸過程實現(xiàn)起來比較復(fù)雜,然而CTE為我們提供了簡單的語法來簡化這一過程。
       
    實現(xiàn)遞歸的CTE語法如下:

     

    [ WITH <common_table_expression> [ ,n ] ]
    <common_table_expression>::=
            expression_name 
    [ ( column_name [ ,n ] ) ]
        
    AS (
           CTE_query_definition1  
    --  定位點成員(也就是初始值或第一個結(jié)果集) 
           union all
           CTE_query_definition2  
    --  遞歸成員
        )

        下面是使用遞歸CTE來獲得“遼寧省”及下面所有市、區(qū)的信息的SQL語句:

     

    with
    district 
    as 
    (
        
    --  獲得第一個結(jié)果集,并更新最終結(jié)果集
        select * from t_tree where node_name= N'遼寧省'
        
    union all
        
    --  下面的select語句首先會根據(jù)從上一個查詢結(jié)果集中獲得的id值來查詢parent_id         
        --  字段的值,然后district就會變當(dāng)前的查詢結(jié)果集,并繼續(xù)執(zhí)行下面的select 語句
        --  如果結(jié)果集不為null,則與最終的查詢結(jié)果合并,同時用合并的結(jié)果更新最終的查
        --  詢結(jié)果;否則停止執(zhí)行。最后district的結(jié)果集就是最終結(jié)果集。
        select a.* from t_tree a, district b
                   
    where a.parent_id = b.id
    )
    select * from district

        查詢后的結(jié)果如下圖所示。

        下面的CTE查詢了非葉子節(jié)點:

     

    with
    district 
    as 
    (
        
    select * from t_tree where node_name= N'遼寧省'
        
    union all
        
    select a.* from t_tree a, district b
                   
    where a.parent_id = b.id
    ),
    district1 
    as
    (
        
    select a.* from district a where a.id in (select parent_id from district)    
    )
    select * from district1

        查詢結(jié)果如下圖所示。

        注:只有“遼寧省”和“沈陽市”有下子節(jié)點。

        在定義和使用遞歸CTE時應(yīng)注意如下幾點

    1. 遞歸 CTE 定義至少必須包含兩個 CTE 查詢定義,一個定位點成員和一個遞歸成員。可以定義多個定位點成員和遞歸成員;但必須將所有定位點成員查詢定義置于第一個遞歸成員定義之前。所有 CTE 查詢定義都是定位點成員,但它們引用 CTE 本身時除外。
    2. 
    定位點成員必須與以下集合運算符之一結(jié)合使用:UNION ALLUNIONINTERSECT EXCEPT。在最后一個定位點成員和第一個遞歸成員之間,以及組合多個遞歸成員時,只能使用 UNION ALL 集合運算符。
    3. 
    定位點成員和遞歸成員中的列數(shù)必須一致。
    4. 遞歸成員中列的數(shù)據(jù)類型必須與定位點成員中相應(yīng)列的數(shù)據(jù)類型一致。
    5. 
    遞歸成員的 FROM 子句只能引用一次 CTE expression_name
    6. 在遞歸成員的 CTE_query_definition 中不允許出現(xiàn)下列項:

    1SELECT DISTINCT

    2GROUP BY

    3HAVING

    4)標(biāo)量聚合

    5TOP

    6LEFTRIGHTOUTER JOIN(允許出現(xiàn) INNER JOIN

    7)子查詢

    8)應(yīng)用于對 CTE_query_definition 中的 CTE 的遞歸引用的提示。

    7. 無論參與的 SELECT 語句返回的列的為空性如何,遞歸 CTE 返回的全部列都可以為空。
    8. 如果遞歸 CTE 組合不正確,可能會導(dǎo)致無限循環(huán)。例如,如果遞歸成員查詢定義對父列和子列返回相同的值,則會造成無限循環(huán)。可以使用 MAXRECURSION 提示以及在 INSERTUPDATEDELETE SELECT 語句的 OPTION 子句中的一個 0 32,767 之間的值,來限制特定語句所允許的遞歸級數(shù),以防止出現(xiàn)無限循環(huán)。這樣就能夠在解決產(chǎn)生循環(huán)的代碼問題之前控制語句的執(zhí)行。服務(wù)器范圍內(nèi)的默認值是 100。如果指定 0,則沒有限制。每一個語句只能指定一個 MAXRECURSION 值。
    9. 不能使用包含遞歸公用表表達式的視圖來更新數(shù)據(jù)。
    10. 可以使用 CTE 在查詢上定義游標(biāo)。遞歸 CTE 只允許使用快速只進游標(biāo)和靜態(tài)(快照)游標(biāo)。如果在遞歸 CTE 中指定了其他游標(biāo)類型,則該類型將轉(zhuǎn)換為靜態(tài)游標(biāo)類型。
    11. 可以在 CTE 中引用遠程服務(wù)器中的表。如果在 CTE 的遞歸成員中引用了遠程服務(wù)器,那么將為每個遠程表創(chuàng)建一個假脫機,這樣就可以在本地反復(fù)訪問這些表。

    下一篇:
    SQL Server2005雜談(3):四個排名函數(shù)(row_number、rank、dense_rank和ntile)的比較





    Android開發(fā)完全講義(第2版)(本書版權(quán)已輸出到臺灣)

    http://product.dangdang.com/product.aspx?product_id=22741502



    Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


    新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

    posted on 2009-02-01 23:42 銀河使者 閱讀(2660) 評論(0)  編輯  收藏 所屬分類: SQL Serverdatabases 原創(chuàng)

    主站蜘蛛池模板: 97人妻精品全国免费视频| 一区二区3区免费视频| 国产午夜亚洲精品理论片不卡| 国产啪精品视频网站免费尤物 | 成人浮力影院免费看| 国产成人综合久久精品亚洲| 亚洲av无码潮喷在线观看| 免费毛片网站在线观看| 无码国产精品一区二区免费vr| 男男gay做爽爽的视频免费| 亚洲国产精品lv| 亚洲成av人片在线观看天堂无码 | 亚洲w码欧洲s码免费| 日韩在线视频线视频免费网站| 亚洲熟妇AV日韩熟妇在线| 亚洲毛片无码专区亚洲乱| 久久精品国产亚洲AV麻豆王友容 | 国产精品亚洲AV三区| 亚洲最大av资源站无码av网址| 亚洲福利视频网站| 亚洲丝袜美腿视频| 亚洲av女电影网| 亚洲免费视频网站| 亚洲人成在线电影| 亚洲人成依人成综合网| 亚洲视频在线免费看| 亚洲综合一区二区精品久久| 亚洲av日韩av不卡在线观看| 亚洲AV无码久久寂寞少妇| 亚洲av无码国产精品色午夜字幕| 亚洲Av无码专区国产乱码DVD | 成在线人免费无码高潮喷水| 一级一级毛片免费播放| 有码人妻在线免费看片| 一级女性全黄生活片免费看| xxxx日本在线播放免费不卡| 国产精品永久免费视频| 中国性猛交xxxxx免费看| 在线观看免费无码视频| 久久成人免费大片| 免费A级毛片无码视频|