posts - 262,  comments - 221,  trackbacks - 0
          目錄:
          =========================================
          1.使用偽列Level顯示表中節(jié)點(diǎn)的層次關(guān)系
          2.統(tǒng)計(jì)表中節(jié)點(diǎn)的層數(shù)
          3.統(tǒng)計(jì)表中各個(gè)層次的節(jié)點(diǎn)數(shù)量
          4.查找表中各個(gè)層次的節(jié)點(diǎn)信息
          5.在Start with中使用子查詢
          6.判斷節(jié)點(diǎn)和節(jié)點(diǎn)之間是否具有層次關(guān)系
          7.刪除級(jí)聯(lián)表中的子樹

          一、使用偽列Level顯示表中節(jié)點(diǎn)的層次關(guān)系:

          Oracle9i對(duì)級(jí)聯(lián)查詢的支持不僅在于提供了像Start with...Connect by這樣的子句供我們很方便地執(zhí)行查詢,而且還提供了一個(gè)偽列(Pseudocolumn): Level。這個(gè)偽列的作用是在遞歸查詢的結(jié)果中用來表示節(jié)點(diǎn)在整個(gè)結(jié)構(gòu)中所處的層次。下面我們來看看實(shí)際的例子:

          還是上次那個(gè)employee表,現(xiàn)在我們要在上次的需求上面增加點(diǎn)小玩意:輸出每個(gè)節(jié)點(diǎn)的層次值,看如下SQL:
          SQL> select level, id, emp_name, manager_id from employee start with id = 2 connect by prior id = ma
          nager_id 
          order by id;

               
          LEVEL         ID EMP_NAME             MANAGER_ID
          ---------- ---------- -------------------- ----------
                   1          2 mark                          1
                   
          2          4 tom                           2
                   
          2          5 paul                          2
                   
          3          7 ben                           4

          SQL
          > 

          我們可以看到在LEVEL列,輸出了1,2,2,3的值,這就是Oracle為我們提供的一個(gè)偽列。此偽列只能用在start with...connect by子句中,下面我們來看另一種方式是否可行:
          SQL> select level, p.* from (select * from employee start with id = 2 connect by prior id = manager_
          id 
          order by id) p;

               
          LEVEL         ID EMP_NAME             MANAGER_ID
          ---------- ---------- -------------------- ----------
                   0          2 mark                          1
                   
          0          4 tom                           2
                   
          0          5 paul                          2
                   
          0          7 ben                           4

          SQL
          > 

          可以看到Level列的值全部變成了0,可見在這里Oracle并不認(rèn)為虛表P里面的數(shù)據(jù)是“層次關(guān)系”,因而對(duì)于Level都返回0

          二、統(tǒng)計(jì)表中節(jié)點(diǎn)的層數(shù):

          假設(shè)現(xiàn)在我們想看一下當(dāng)前employee表中員工總共分為幾個(gè)級(jí)別,我們應(yīng)該如何做呢?請(qǐng)看下面的SQL
          SQL> select * from employee;

                  ID EMP_NAME             MANAGER_ID
          ---------- -------------------- ----------
                   1 king
                   
          2 mark                          1
                   
          3 bob                           1
                   
          4 tom                           2
                   
          5 paul                          2
                   
          6 jack                          3
                   
          7 ben                           4

          7 rows selected.

          SQL
          > 
          SQL
          > 
          SQL
          > select count(levelfrom employee start with manager_id is null connect by prior id = manager_i
          d;

          COUNT(LEVEL)
          ------------
                     7

          SQL
          > 
          SQL
          > select count(distinct levelfrom employee start with manager_id is null connect by prior id = 
          manager_id;

          COUNT(DISTINCTLEVEL)
          --------------------
                     4

          從這里我們可以看到,在統(tǒng)計(jì)的時(shí)候一定要使用distinct關(guān)鍵字,否則得到的錯(cuò)誤的結(jié)果。

          三、統(tǒng)計(jì)表中各個(gè)層次的節(jié)點(diǎn)數(shù)量:

          假設(shè)我們想知道employee表中每個(gè)級(jí)別的員工數(shù)量,我們應(yīng)該如何做呢--對(duì)了,使用Level和group by子句了
          SQL> select levelcount(levelfrom employee start with manager_id is null connect by prior id = ma
          nager_id 
          group by level;

               
          LEVEL COUNT(LEVEL)
          ---------- ------------
                   1            1
                   
          2            2
                   
          3            3
                   
          4            1

          四、查找表中各個(gè)層次的節(jié)點(diǎn)信息:

          上面的例子很簡單,我們看到Level可以用在group by子句中,現(xiàn)在我們更進(jìn)一步,查看指定層次的員工信息,比如說我現(xiàn)在打算查看Level=2的所有員工的記錄,應(yīng)該如何做呢?很自然地我們想到了第一個(gè)SQL語句:
          SQL> select level, id, emp_name, manager_id from employee where level >= 2;

          no rows selected

          很奇怪吧,這這里level關(guān)鍵字就不起作用了,這是因?yàn)閘evel偽列只能在和start with...connect by子句結(jié)合時(shí)才能發(fā)揮作用,就想上面的統(tǒng)計(jì)各層節(jié)點(diǎn)數(shù)量一樣,于是我們又立馬想到了第二個(gè)SQL語句:
          select *
            
          from (select level, id, emp_name, manager_id
                    
          from employee
                   start 
          with manager_id is null
                  connect 
          by prior id = manager_id
                   
          order by id) p
           
          where p.level = 2

          看起來這個(gè)句子沒有什么問題吧,實(shí)際執(zhí)行的效果如何呢?我們?cè)赟QL*PLUS下執(zhí)行,結(jié)果卻是報(bào)錯(cuò):
          ERROR at line 1:
          ORA
          -01747: invalid user.table.columntable.columnor column specification

          很郁悶!為什么會(huì)報(bào)p.level不可識(shí)別呢?這是因?yàn)閘evel是Oracle的偽列,并不屬于任何一個(gè)表,我們必須使用別名把這個(gè)偽列“偽裝”成一個(gè)實(shí)際的列,現(xiàn)在我們看第三個(gè)語句,注意語句高亮處。
          SQL> select *
            
          2    from (select level emp_level , id, emp_name, manager_id
            
          3            from employee
            
          4           start with manager_id is null
            
          5          connect by prior id = manager_id
            
          6           order by id) p
            
          7   where p.emp_level = 2;

           EMP_LEVEL         ID EMP_NAME             MANAGER_ID
          ---------- ---------- -------------------- ----------
                   2          2 mark                          1
                   
          2          3 bob                           1

          SQL
          > 

          這次終于搞定了!不過實(shí)際上我們有更簡單的解決方法,請(qǐng)看第四個(gè)SQL語句:
          SQL> select level, id, emp_name, manager_id
            
          2    from employee
            
          3   where level = 2
            
          4   start with manager_id is null
            
          5  connect by prior id = manager_id
            
          6   order by id;

               
          LEVEL         ID EMP_NAME             MANAGER_ID
          ---------- ---------- -------------------- ----------
                   2          2 mark                          1
                   
          2          3 bob                           1

          上面我們是查看某個(gè)層次的所有節(jié)點(diǎn)信息,現(xiàn)在我們打算看看所有層次的節(jié)點(diǎn)信息,而且要求用一種直觀的信息顯示出來。下面的例子演示了如何使用空格縮進(jìn)的方式來直觀顯示節(jié)點(diǎn)之間的層次關(guān)系:
          SQL> select level, id, lpad('  '2 * (level - 1)) || emp_name name, manager_id
            
          2    from employee
            
          3   start with manager_id is null
            
          4  connect by prior id = manager_id;

               
          LEVEL         ID NAME                 MANAGER_ID
          ---------- ---------- -------------------- ----------
                   1          1 king
                   
          2          2   mark                        1
                   
          3          4     tom                       2
                   
          4          7       ben                     4
                   
          3          5     paul                      2
                   
          2          3   bob                         1
                   
          3          6     jack                      3

          7 rows selected.

          請(qǐng)注意這里的lpad函數(shù)的作用,正是它利用了層次和空格進(jìn)行縮進(jìn),讓我們可以很直觀地從NAME字段對(duì)齊方式就知道各個(gè)節(jié)點(diǎn)的層次關(guān)系。如果我們需要過濾其中的某些節(jié)點(diǎn),只需要將where條件加在start with前面就可以了(注意必須是前面,否則會(huì)報(bào)語法錯(cuò)誤)。

          五、在Start with中使用子查詢:

          在前面我們看到的例子中,start with的值都是一個(gè)固定的內(nèi)容,但有些時(shí)候查詢的起始點(diǎn)并不容易確定,比如:查詢工號(hào)最小的員工節(jié)點(diǎn)及其子節(jié)點(diǎn),這個(gè)時(shí)候工號(hào)最小很明顯是一個(gè)查詢的條件,需要我們先通過執(zhí)行一個(gè)查詢得到確定的值,再作為查詢的起點(diǎn)。請(qǐng)看例子:
          SQL> select level, id, lpad('  '2 * (level - 1)) || emp_name name, manager_id
            
          2    from employee
            
          3   start with id = (select min(id) from employee)
            
          4  connect by prior id = manager_id;

               
          LEVEL         ID NAME                 MANAGER_ID
          ---------- ---------- -------------------- ----------
                   1          1 king
                   
          2          2   mark                        1
                   
          3          4     tom                       2
                   
          4          7       ben                     4
                   
          3          5     paul                      2
                   
          2          3   bob                         1
                   
          3          6     jack                      3

          7 rows selected.

          六、判斷節(jié)點(diǎn)和節(jié)點(diǎn)之間是否具有層次關(guān)系:

          在日常工作中除了查詢節(jié)點(diǎn)的信息之外,另一個(gè)常見的應(yīng)用就是判斷某個(gè)節(jié)點(diǎn)和另外一個(gè)/些節(jié)點(diǎn)之間是否具有層次關(guān)系。例如我想知道員工mark是不是員工jack的領(lǐng)導(dǎo)(直接或間接的都可以),我應(yīng)該怎么做呢?

          考慮到start with...connect by會(huì)返回一棵節(jié)點(diǎn)樹,假如節(jié)點(diǎn)數(shù)上沒有jack節(jié)點(diǎn),那么說明mark并不是jack的直接或間接領(lǐng)導(dǎo),如果找到那說明mark是jack的父節(jié)點(diǎn)。方法簡單
          SQL> select level,
            
          2         id,
            
          3         lpad('  '2 * (level - 1)) || emp_name employee_name,
            
          4         manager_id
            
          5    from employee
            
          6   where emp_name = 'jack'
            
          7   start with emp_name = 'mark'
            
          8  connect by prior id = manager_id;

          no rows selected

          七、刪除級(jí)聯(lián)表中的子樹:

          假設(shè)現(xiàn)在employee表中的mark及其下屬員工離職,那么我們?yōu)榱司S護(hù)數(shù)據(jù)的完整性,必須將mark及其下屬員工的節(jié)點(diǎn)都刪除,有了start with...connect by和level我們就可以輕松地做到這一點(diǎn)了。

          【1】按名稱刪除節(jié)點(diǎn)樹:
          SQL> delete from employee
            
          2   where id in (select id
            
          3                  from employee
            
          4                 start with emp_name = 'mark'
            
          5                connect by prior id = manager_id);

          4 rows deleted.

          【2】按層次刪除節(jié)點(diǎn)樹:

          從上面的例子我們知道只需要在第一個(gè)SQL的基礎(chǔ)上改變一下:使用level區(qū)分節(jié)點(diǎn)的層次就做到了。

          參考資料:《Mastering Oracle SQL》(By Alan Beaulieu, Sanjay Mishra O'Reilly June 2004  0-596-00632-2)  


          -------------------------------------------------------------
          生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
          posted on 2008-06-12 17:45 Paul Lin 閱讀(3959) 評(píng)論(0)  編輯  收藏 所屬分類: Oracle 開發(fā)
          <2008年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          BlogJava熱點(diǎn)博客

          好友博客

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 湖南省| 五家渠市| 枝江市| 咸宁市| 沿河| 和田县| 苏州市| 达日县| 长乐市| 古交市| 海伦市| 象州县| 河东区| 荆州市| 宝鸡市| 安新县| 汉川市| 仙桃市| 天长市| 墨竹工卡县| 苍溪县| 五常市| 南召县| 会昌县| 五家渠市| 东兰县| 济源市| 岳普湖县| 鹤庆县| 漳州市| 浠水县| 固原市| 广安市| 新建县| 边坝县| 乌拉特前旗| 乌苏市| 大理市| 普格县| 卢龙县| 开原市|