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

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

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

    孤燈野火
    暢想的天空
    posts - 2,comments - 4,trackbacks - 0
    在db2可以使用sql語(yǔ)句來(lái)進(jìn)行遞歸查詢,就是使用with語(yǔ)句

    1.先建一個(gè)樹(shù)形表:

    create table tst (
    id  
    integer,
    parentId 
    int,
    name 
    varchar(20))

    2.插入數(shù)據(jù)
    insert into tst values 
    (
    1,0,'a'),
    (
    2,0,'b'),
    (
    3,1,'c'),
    (
    4,1,'d'),
    (
    5,4,'d'),
    (
    6,5,'d')
    3.使用遞歸查詢
    with rpl (id,parentId,name) as 
    (
    select id,parentId,name from tst  where parentId=1 
    union all 
    select  child.id,child.parentId,child.name from rpl parent, tst child where parent.id=child.parentId
    )
    select * from rpl

    Oracle的遞歸查詢


    收集的幾條在oracle中通過(guò)connect by prior來(lái)實(shí)現(xiàn)遞歸查詢


    Start with...Connect By子句遞歸查詢一般用于一個(gè)表維護(hù)樹(shù)形結(jié)構(gòu)的應(yīng)用。
    創(chuàng)建示例表:
    CREATE TABLE TBL_TEST
    (
    ID    NUMBER,
    NAME VARCHAR2(100 BYTE),
    PID   NUMBER                                  DEFAULT 0
    );

    插入測(cè)試數(shù)據(jù):
    INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('1','10','0');
    INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('2','11','1');
    INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('3','20','0');
    INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('4','12','1');
    INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('5','121','2');

    從Root往樹(shù)末梢遞歸
    select * from TBL_TEST
    start with id=1
    connect by prior id = pid

    從末梢往樹(shù)ROOT遞歸
    select * from TBL_TEST
    start with id=5
    connect by prior pid = id


    ===============================================================================================================

    有一張表   t  
    字段:  
    parent  
    child  
    兩個(gè)字段的關(guān)系是父子關(guān)系  
       
    寫(xiě)一個(gè)sql語(yǔ)句,查詢出指定父下面的所有的子  
       
    比如  
       
    a   b  
    a   c    
    a   e  
    b   b1  
    b   b2  
    c   c1  
    e   e1  
    e   e3  
    d   d1  
       
    指定parent=a,選出  
    a   b  
    a   c    
    a   e  
    b   b1  
    b   b2  
    c   c1  
    e   e1  
    e   e3  
       
    SQL語(yǔ)句:  
    select   parent,child   from   test   start   with   parent='a'  
    connect   by   prior   child=parent


    ================================================================================================

    connect by 是結(jié)構(gòu)化查詢中用到的,其基本語(yǔ)法是:
    select ... from tablename start by cond1
    connect by cond2
    where cond3;
    簡(jiǎn)單說(shuō)來(lái)是將一個(gè)樹(shù)狀結(jié)構(gòu)存儲(chǔ)在一張表里,比如一個(gè)表中存在兩個(gè)字段:
    id,parentid那么通過(guò)表示每一條記錄的parent是誰(shuí),就可以形成一個(gè)樹(shù)狀結(jié)構(gòu)。
    用上述語(yǔ)法的查詢可以取得這棵樹(shù)的所有記錄。
    其中COND1是根結(jié)點(diǎn)的限定語(yǔ)句,當(dāng)然可以放寬限定條件,以取得多個(gè)根結(jié)點(diǎn),實(shí)際就是多棵樹(shù)。
    COND2是連接條件,其中用PRIOR表示上一條記錄,比如 CONNECT BY PRIOR ID=PRAENTID就是說(shuō)上一條記錄的ID是本條記錄的PRAENTID,即本記錄的父親是上一條記錄。
    COND3是過(guò)濾條件,用于對(duì)返回的所有記錄進(jìn)行過(guò)濾。

    PRIOR和START WITH關(guān)鍵字是可選項(xiàng)
    PRIORY運(yùn)算符必須放置在連接關(guān)系的兩列中某一個(gè)的前面。對(duì)于節(jié)點(diǎn)間的父子關(guān)系,PRIOR
    運(yùn)算符在一側(cè)表示父節(jié)點(diǎn),在另一側(cè)表示子節(jié)點(diǎn),從而確定查找樹(shù)結(jié)構(gòu)是的順序是自頂向下還是
    自底向上。在連接關(guān)系中,除了可以使用列名外,還允許使用列表達(dá)式。START WITH 子句為
    可選項(xiàng),用來(lái)標(biāo)識(shí)哪個(gè)節(jié)點(diǎn)作為查找樹(shù)型結(jié)構(gòu)的根節(jié)點(diǎn)。若該子句被省略,則表示所有滿足查詢
    條件的行作為根節(jié)點(diǎn)。
    完整的例子如SELECT PID,ID,NAME FROM T_WF_ENG_WFKIND START WITH PID =0 CONNECT BY PRIOR ID = PID


    以上主要是針對(duì)上層對(duì)下層的順向遞歸查詢而使用start with ... connect by prior ...這種方式,但有時(shí)在需求需要的時(shí)候,可能會(huì)需要由下層向上層的逆向遞歸查詢,此是語(yǔ)句就有所變化:例如要實(shí)現(xiàn) select * from table where id in ('0','01','0101','0203','0304') ;現(xiàn)在想把0304的上一級(jí)03給遞歸出來(lái),0203的上一級(jí)02給遞歸出來(lái),而01現(xiàn)在已經(jīng)是存在的,最高層為0.而這張table不僅僅這些數(shù)據(jù),但我現(xiàn)在只需要('0','01','0101','0203','0304','02','03')這些數(shù)據(jù),此時(shí)語(yǔ)句可以這樣寫(xiě)SELECT PID,ID,NAME FROM V_WF_WFKIND_TREE WHERE ID IN (SELECT DISTINCT(ID) ID FROM V_WF_WFKIND_TREE CONNECT BY PRIOR PID = ID START WITH ID IN ('0','01','0101','0203','0304') );

    其中START WITH ID IN里面的值也可以替換SELECT 子查詢語(yǔ)句.


    注意由上層向下層遞歸與下層向上層遞歸的區(qū)別在于START WITH...CONNECT BY PRIOR...的先后順序以及 ID = PID 和 PID = ID 的微小變化!

    =============================================================
    connect by prior start with 經(jīng)常會(huì)被用到一個(gè)表中存在遞歸關(guān)系的時(shí)候。比如我們經(jīng)常會(huì)將一個(gè)比較復(fù)雜的目錄樹(shù)存儲(chǔ)到一個(gè)表中。或者將一些部門(mén)存儲(chǔ)到一個(gè)表中,而這些部門(mén)互相有隸屬關(guān)系。這個(gè)時(shí)候你就會(huì)用到connect by prior start with。

    典型的使用方法就是:
    select * from table connect by prior cur_id=parent_id start with cur_id=???
    例如:
    a            b
    1           0
    2           1
    3           1
    4           2
    5           3

    如果想查找a=2及其下面的所有數(shù)據(jù),則:
    select * from table connect by prior a=b start with a=2
    a           b
    2           1
    4           2

    這些只是基礎(chǔ),皮毛。其實(shí)只要你靈活的構(gòu)造查詢語(yǔ)句。可以得出意想不到的結(jié)果。比如生成樹(shù)每一個(gè)路徑。
    但是這些記錄組成的樹(shù)必須正常才可以。如果有互為父子的情況,就會(huì)出現(xiàn)循環(huán)錯(cuò)誤!

     

    select * from tb_cus_area_cde

    --子取父
    select * from tb_cus_area_cde a   
    CONNECT BY PRIOR     a.c_snr_area=a.c_area_cde START WITH a.c_area_cde='1040101'

    --父取子
    select * from tb_cus_area_cde a   
    CONNECT BY PRIOR     a.c_area_cde=a.c_snr_area START WITH a.c_snr_area is null

     

    注意:在用這個(gè)函數(shù)的時(shí)候,statement的參數(shù)要用 ResultSet.TYPE_SCROLL_INSENSITIVE   而不能用 ResultSet.TYPE_SCROLL_SENSITIVE,在這里再把這兩個(gè)之間的區(qū)別講講:

    1.TYPE_FORWORD_ONLY,只可向前滾動(dòng);  
       
    2.TYPE_SCROLL_INSENSITIVE,雙向滾動(dòng),但不及時(shí)更新,就是如果數(shù)據(jù)庫(kù)里的數(shù)據(jù)修改過(guò),并不在ResultSet中反應(yīng)出來(lái)。  
       
    3.TYPE_SCROLL_SENSITIVE,雙向滾動(dòng),并及時(shí)跟蹤數(shù)據(jù)庫(kù)的更新,以便更改ResultSet中的數(shù)據(jù)

     


    ======================================
    10g樹(shù)形查詢特性CONNECT_BY_ISCYCLE

         在10g中Oracle提供了新的偽列:CONNECT_BY_ISCYCLE,通過(guò)這個(gè)偽列,可以判斷是否在樹(shù)形查詢的過(guò)程中構(gòu)成了循環(huán),這個(gè)偽列只是在CONNECT BY NOCYCLE方式下有效。

      這一篇描述一下解決問(wèn)題的思路。

      CONNECT_BY_ISCYCLE的實(shí)現(xiàn)和前面兩篇文章中CONNECT_BY_ROOT和CONNECT_BY_ISLEAF的實(shí)現(xiàn)完全不同。

      因?yàn)橐獙?shí)現(xiàn)CONNECT_BY_ISCYCLE,就必須先實(shí)現(xiàn)CONNECT BY NOCYCLE,而在9i中是沒(méi)有方法實(shí)現(xiàn)這個(gè)功能的。

      也就是說(shuō),首先要實(shí)現(xiàn)自己的樹(shù)形查詢的功能,而僅這第一點(diǎn),就是一個(gè)異常困難的問(wèn)題,何況后面還要實(shí)現(xiàn)NOCYCLE,最后再加上一個(gè)ISCYCLE的判斷。

      所以總的來(lái)說(shuō),這個(gè)功能的實(shí)現(xiàn)比前面兩個(gè)功能要復(fù)雜得多。由于樹(shù)形查詢的LEVEL是不固定的,所以采用鏈接的方式實(shí)現(xiàn),基本上是不現(xiàn)實(shí)的。換句話說(shuō),用純SQL的方式來(lái)實(shí)現(xiàn)樹(shù)形查詢的功能基本上不可行。而為了解決這個(gè)功能,只能通過(guò)PL/SQL配合SQL來(lái)實(shí)現(xiàn)。

      仍然是首先構(gòu)造一個(gè)例子:

    SQL> CREATE TABLE T_TREE (ID NUMBER, FATHER_ID NUMBER, NAME VARCHAR2(30));
      表已創(chuàng)建。
      SQL> INSERT INTO T_TREE VALUES (1, 0, 'A');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (2, 1, 'BC');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (3, 1, 'DE');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (4, 1, 'FG');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (5, 2, 'HIJ');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (6, 4, 'KLM');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (7, 6, 'NOPQ');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (0, 0, 'ROOT');
      已創(chuàng)建 1 行。
      SQL> INSERT INTO T_TREE VALUES (4, 7, 'FG');
      已創(chuàng)建 1 行。
      SQL> COMMIT;
      提交完成。
      SQL> SELECT * FROM T_TREE;
      ID FATHER_ID NAME
      ---------- ---------- ------------------------------
      1 0 A
      2 1 BC
      3 1 DE
      4 1 FG
      5 2 HIJ
      6 4 KLM
      7 6 NOPQ
      0 0 ROOT
      4 7 FG
      已選擇9行。

      上面構(gòu)造了兩種樹(shù)形查詢循環(huán)的情況,一種是當(dāng)前記錄的自循環(huán),另一種是樹(shù)形查詢的某個(gè)子節(jié)點(diǎn)是當(dāng)前節(jié)點(diǎn)的祖先節(jié)點(diǎn),從而構(gòu)成了循環(huán)。在這個(gè)例子中,記錄ID為0和ID為4且FATHER_ID等于7的兩條記錄分別構(gòu)成了上述的兩種循環(huán)的情況。

      下面就來(lái)看看CONNECT_BY_ISCYCLE和CONNECT BY NOCYCLE的功能:

    SQL> SELECT *
      2 FROM T_TREE
      3 START WITH ID = 0
      4 CONNECT BY PRIOR ID = FATHER_ID;
      ERROR:
      ORA-01436: 用戶數(shù)據(jù)中的 CONNECT BY 循環(huán)
      未選定行
      SQL> SELECT *
      2 FROM T_TREE
      3 START WITH ID = 1
      4 CONNECT BY PRIOR ID = FATHER_ID;
      ERROR:
      ORA-01436: 用戶數(shù)據(jù)中的 CONNECT BY 循環(huán)
      未選定行


      這就是不使用CONNECT BY NOCYCLE的情況,查詢會(huì)報(bào)錯(cuò),指出樹(shù)形查詢中出現(xiàn)循環(huán),在10g中可以使用CONNECT BY NOCYCLE的方式來(lái)避免錯(cuò)誤的產(chǎn)生:

    SQL> SELECT *
      2 FROM T_TREE
      3 START WITH ID = 0
      4 CONNECT BY NOCYCLE PRIOR ID = FATHER_ID;
      ID FATHER_ID NAME
      ---------- ---------- ------------------------------
      0 0 ROOT
      1 0 A
      2 1 BC
      5 2 HIJ
      3 1 DE
      4 1 FG
      6 4 KLM
      7 6 NOPQ
      已選擇8行。


      使用CONNECT BY NOCYCLE,Oracle自動(dòng)避免循環(huán)的產(chǎn)生,將不產(chǎn)生循環(huán)的數(shù)據(jù)查詢出來(lái),下面看看CONNECT_BY_ISCYCLE的功能:

    SQL> SELECT ID,
      2 FATHER_ID,
      3 NAME,
      4 CONNECT_BY_ISCYCLE CYCLED
      5 FROM T_TREE
      6 START WITH ID = 0
      7 CONNECT BY NOCYCLE PRIOR ID = FATHER_ID;
      ID FATHER_ID NAME CYCLED
      ---------- ---------- ------------------------------ ----------
      0 0 ROOT 1
      1 0 A 0
      2 1 BC 0
      5 2 HIJ 0
      3 1 DE 0
      4 1 FG 0
      6 4 KLM 0
      7 6 NOPQ 1
      已選擇8行。


      可以看到,CONNECT_BY_ISCYCLE偽列指出循環(huán)在樹(shù)形查詢中發(fā)生的位置。

      為了實(shí)現(xiàn)CONNECT_BY_ISCYCLE就必須先實(shí)現(xiàn)CONNECT BY NOCYCLE方式,而這在9i中是沒(méi)有現(xiàn)成的辦法的,所以這里嘗試使用PL/SQL來(lái)自己實(shí)現(xiàn)樹(shù)形查詢的功能。

    SQL> CREATE OR REPLACE FUNCTION F_FIND_CHILD(P_VALUE VARCHAR2) RETURN VARCHAR2 AS
      2 V_STR VARCHAR2(32767) := '/' || P_VALUE;
      3
      4 PROCEDURE P_GET_CHILD_STR (P_FATHER IN VARCHAR2, P_STR IN OUT VARCHAR2) AS
      5 BEGIN
      6 FOR I IN (SELECT ID FROM T_TREE WHERE FATHER_ID = P_FATHER AND FATHER_ID != ID) LOOP
      7 IF INSTR(P_STR || '/', '/' || I.ID || '/') = 0 THEN
      8 P_STR := P_STR || '/' || I.ID;
      9 P_GET_CHILD_STR(I.ID, P_STR);
      10 END IF;
      11 END LOOP;
      12 END;
      13 BEGIN
      14 P_GET_CHILD_STR(P_VALUE, V_STR);
      15 RETURN V_STR;
      16 END;
      17 /


      函數(shù)已創(chuàng)建。

      構(gòu)造一個(gè)函數(shù),在函數(shù)中遞歸調(diào)用過(guò)程來(lái)實(shí)現(xiàn)樹(shù)形查詢的功能。

      下面看看調(diào)用這個(gè)函數(shù)的結(jié)果: 

    SQL> SELECT F_FIND_CHILD(0) FROM DUAL;
      F_FIND_CHILD(0)
      ------------------------------------------------
      /0/1/2/5/3/4/6/7
      SQL> SELECT F_FIND_CHILD(2) FROM DUAL;
      F_FIND_CHILD(2)
      ------------------------------------------------
      /2/5
      SQL> SELECT F_FIND_CHILD(4) FROM DUAL;
      F_FIND_CHILD(4)
      ------------------------------------------------
      /4/6/7


      雖然目前存在的問(wèn)題還有很多,但是已經(jīng)基本上實(shí)現(xiàn)了一個(gè)最簡(jiǎn)單的NOCYCLE的SYS_CONNECT_BY_PATH的功能。

      有了這個(gè)函數(shù)作為基礎(chǔ),就可以逐步的實(shí)現(xiàn)最終的目標(biāo)了。


    posted on 2011-05-09 16:28 孤飛燕 閱讀(1726) 評(píng)論(1)  編輯  收藏 所屬分類: 數(shù)據(jù)庫(kù)

    FeedBack:
    # re: 數(shù)據(jù)庫(kù)遞歸查詢[未登錄](méi)
    2012-02-29 13:18 | 123
    謝謝!。。 拿走了  回復(fù)  更多評(píng)論
      
    主站蜘蛛池模板: 日韩免费观看视频| 久久精品国产免费观看| 亚洲国产精品嫩草影院久久| 亚洲国产日韩a在线播放| 亚洲Aⅴ无码一区二区二三区软件| 亚洲伊人久久大香线蕉结合| 精品国产无限资源免费观看| 亚洲国产成人久久综合一区| h视频在线观看免费网站| 亚洲伊人久久大香线蕉| 成人毛片18女人毛片免费96| 亚洲中文字幕久久精品无码A | 免费无码黄网站在线看| 久久久久久国产a免费观看黄色大片 | 国产免费变态视频网址网站| 国产亚洲视频在线观看网址| 亚洲国产精品人人做人人爱| 国产免费一级高清淫曰本片| 亚洲av中文无码乱人伦在线r▽| 免费A级毛片av无码| 国产.亚洲.欧洲在线| 午夜免费福利在线观看| 色哟哟国产精品免费观看 | 亚洲综合图片小说区热久久| 免费精品国偷自产在线在线 | 三级网站免费观看| 妞干网免费视频在线观看| 久久亚洲AV成人无码国产电影| yy6080久久亚洲精品| 中文字幕无码日韩专区免费| 日韩精品亚洲人成在线观看 | 性感美女视频免费网站午夜| 免费人成视频在线播放| 亚洲国产另类久久久精品| 在线看片韩国免费人成视频| 麻豆一区二区三区蜜桃免费| 亚洲成av人在线视| 成人毛片手机版免费看| a级毛片黄免费a级毛片| 国产成人精品日本亚洲网址| a级亚洲片精品久久久久久久 |