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

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

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

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

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

    本文為原創,如需轉載,請注明作者和出處,謝謝!

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

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

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

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

    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       大東區        2

    5       沈河區        2

    6       鐵西區        2

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

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

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

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

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

     

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

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

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

     

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

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

     

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

        查詢后的結果如下圖所示。

        下面的CTE查詢了非葉子節點:

     

    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

        查詢結果如下圖所示。

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

        在定義和使用遞歸CTE時應注意如下幾點

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

    1SELECT DISTINCT

    2GROUP BY

    3HAVING

    4)標量聚合

    5TOP

    6LEFTRIGHTOUTER JOIN(允許出現 INNER JOIN

    7)子查詢

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

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

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





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

    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 原創

    主站蜘蛛池模板: 永久免费看bbb| 国产一精品一av一免费爽爽| 久久嫩草影院免费看夜色| 最近中文字幕mv免费高清视频7 | 国产精品亚洲а∨天堂2021| 最近中文字幕mv免费高清在线| 亚洲国产精品碰碰| 亚洲熟女www一区二区三区| 亚洲欧洲免费视频| 亚洲天堂一区二区| 免费国产成人午夜在线观看| 亚洲毛片基地4455ww| 69成人免费视频| 亚洲黄色三级网站| 亚洲一区二区在线免费观看| 亚洲天然素人无码专区| 亚洲精品无码不卡在线播HE| 高清永久免费观看| 亚洲成AV人片在线观看无码| 97无码人妻福利免费公开在线视频| 亚洲国产婷婷六月丁香| 美女视频黄是免费的网址| 久久亚洲最大成人网4438| 久久久久无码专区亚洲av| 中国性猛交xxxxx免费看| 亚洲一区精品视频在线| 成人免费男女视频网站慢动作| a级毛片在线免费观看| 久久亚洲私人国产精品| 中文字幕影片免费在线观看| 亚洲爆乳AAA无码专区| 四虎永久免费网站免费观看| 久青草国产免费观看| 亚洲成a人片在线观看无码| 国产免费AV片无码永久免费| 3344永久在线观看视频免费首页| 中文字幕在线日亚洲9| 亚洲无码精品浪潮| 最近中文字幕大全中文字幕免费| 精品国产污污免费网站入口在线| 久久久久久亚洲av无码蜜芽|