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

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

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

    瘋狂

    STANDING ON THE SHOULDERS OF GIANTS
    posts - 481, comments - 486, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    connect by prior

    Posted on 2011-05-06 11:25 瘋狂 閱讀(7186) 評論(0)  編輯  收藏 所屬分類: database

    收集的幾條在oracle中通過connect by prior來實現遞歸查詢

      Start with...Connect By子句遞歸查詢一般用于一個表維護樹形結構的應用。

      創建示例表:

      CREATE TABLE TBL_TEST

      (

      ID    NUMBER,

      NAME VARCHAR2(100 BYTE),

      PID   NUMBER                                  DEFAULT 0

      );

      插入測試數據:

      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往樹末梢遞歸

      select * from TBL_TEST

      start with id=1

      connect by prior id = pid

      從末梢往樹ROOT遞歸

      select * from TBL_TEST

      start with id=5

      connect by prior pid = id

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

      有一張表   t

      字段:

      parent

      child

      兩個字段的關系是父子關系

      寫一個sql語句,查詢出指定父下面的所有的子

      比如

      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語句:

      select   parent,child   from   test   start   with   parent='a'

      connect   by   prior   child=parent

    [1] [2] [3] [4] 下一頁

      connect by 是結構化查詢中用到的,其基本語法是:

      select ... from tablename start by cond1

      connect by cond2

      where cond3;

      簡單說來是將一個樹狀結構存儲在一張表里,比如一個表中存在兩個字段:

      id,parentid那么通過表示每一條記錄的parent是誰,就可以形成一個樹狀結構。

      用上述語法的查詢可以取得這棵樹的所有記錄。

      其中COND1是根結點的限定語句,當然可以放寬限定條件,以取得多個根結點,實際就是多棵樹。

      COND2是連接條件,其中用PRIOR表示上一條記錄,比如 CONNECT BY PRIOR ID=PRAENTID就是說上一條記錄的ID是本條記錄的PRAENTID,即本記錄的父親是上一條記錄。

      COND3是過濾條件,用于對返回的所有記錄進行過濾。

      PRIOR和START WITH關鍵字是可選項

      PRIORY運算符必須放置在連接關系的兩列中某一個的前面。對于節點間的父子關系,PRIOR

      運算符在一側表示父節點,在另一側表示子節點,從而確定查找樹結構是的順序是自頂向下還是

      自底向上。在連接關系中,除了可以使用列名外,還允許使用列表達式。START WITH 子句為

      可選項,用來標識哪個節點作為查找樹型結構的根節點。若該子句被省略,則表示所有滿足查詢

      條件的行作為根節點。

      完整的例子如SELECT PID,ID,NAME FROM T_WF_ENG_WFKIND START WITH PID =0 CONNECT BY PRIOR ID = PID

      以上主要是針對上層對下層的順向遞歸查詢而使用start with ... connect by prior ...這種方式,但有時在需求需要的時候,可能會需要由下層向上層的逆向遞歸查詢,此是語句就有所變化:例如要實現 select * from table where id in ('0','01','0101','0203','0304') ;現在想把0304的上一級03給遞歸出來,0203的上一級02給遞歸出來,而01現在已經是存在的,最高層為0.而這張table不僅僅這些數據,但我現在只需要('0','01','0101','0203','0304','02','03')這些數據,此時語句可以這樣寫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 子查詢語句.

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

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

      connect by prior start with 經常會被用到一個表中存在遞歸關系的時候。比如我們經常會將一個比較復雜的目錄樹存儲到一個表中。或者將一些部門存儲到一個表中,而這些部門互相有隸屬關系。這個時候你就會用到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及其下面的所有數據,則:

      select * from table connect by prior a=b start with a=2

      a           b

      2           1

      4           2

      這些只是基礎,皮毛。其實只要你靈活的構造查詢語句。可以得出意想不到的結果。比如生成樹每一個路徑。

      但是這些記錄組成的樹必須正常才可以。如果有互為父子的情況,就會出現循環錯誤!

      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

      注意:在用這個函數的時候,statement的參數要用 ResultSet.TYPE_SCROLL_INSENSITIVE   而不能用 ResultSet.TYPE_SCROLL_SENSITIVE,在這里再把這兩個之間的區別講講:

      1.TYPE_FORWORD_ONLY,只可向前滾動;

      2.TYPE_SCROLL_INSENSITIVE,雙向滾動,但不及時更新,就是如果數據庫里的數據修改過,并不在ResultSet中反應出來。

      3.TYPE_SCROLL_SENSITIVE,雙向滾動,并及時跟蹤數據庫的更新,以便更改ResultSet中的數據
    10g樹形查詢特性CONNECT_BY_ISCYCLE

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

      這一篇描述一下解決問題的思路。

      CONNECT_BY_ISCYCLE的實現和前面兩篇文章中CONNECT_BY_ROOT和CONNECT_BY_ISLEAF的實現完全不同。

      因為要實現CONNECT_BY_ISCYCLE,就必須先實現CONNECT BY NOCYCLE,而在9i中是沒有方法實現這個功能的。

      也就是說,首先要實現自己的樹形查詢的功能,而僅這第一點,就是一個異常困難的問題,何況后面還要實現NOCYCLE,最后再加上一個ISCYCLE的判斷。

      所以總的來說,這個功能的實現比前面兩個功能要復雜得多。由于樹形查詢的LEVEL是不固定的,所以采用鏈接的方式實現,基本上是不現實的。換句話說,用純SQL的方式來實現樹形查詢的功能基本上不可行。而為了解決這個功能,只能通過PL/SQL配合SQL來實現。

      仍然是首先構造一個例子:

      SQL> CREATE TABLE T_TREE (ID NUMBER, FATHER_ID NUMBER, NAME VARCHAR2(30));

      表已創建。

      SQL> INSERT INTO T_TREE VALUES (1, 0, 'A');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (2, 1, 'BC');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (3, 1, 'DE');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (4, 1, 'FG');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (5, 2, 'HIJ');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (6, 4, 'KLM');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (7, 6, 'NOPQ');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (0, 0, 'ROOT');

      已創建 1 行。

      SQL> INSERT INTO T_TREE VALUES (4, 7, 'FG');

      已創建 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行。

      上面構造了兩種樹形查詢循環的情況,一種是當前記錄的自循環,另一種是樹形查詢的某個子節點是當前節點的祖先節點,從而構成了循環。在這個例子中,記錄ID為0和ID為4且FATHER_ID等于7的兩條記錄分別構成了上述的兩種循環的情況。

      下面就來看看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: 用戶數據中的 CONNECT BY 循環

      未選定行

      SQL> SELECT *

      2 FROM T_TREE

      3 START WITH ID = 1

      4 CONNECT BY PRIOR ID = FATHER_ID;

      ERROR:

      ORA-01436: 用戶數據中的 CONNECT BY 循環

      未選定行

      這就是不使用CONNECT BY NOCYCLE的情況,查詢會報錯,指出樹形查詢中出現循環,在10g中可以使用CONNECT BY NOCYCLE的方式來避免錯誤的產生:

      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行。

    上一頁  [1] [2] [3] [4] 下一頁

      使用CONNECT BY NOCYCLE,Oracle自動避免循環的產生,將不產生循環的數據查詢出來,下面看看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偽列指出循環在樹形查詢中發生的位置。

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

      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 /

      函數已創建。

      構造一個函數,在函數中遞歸調用過程來實現樹形查詢的功能。

      下面看看調用這個函數的結果:

      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

      雖然目前存在的問題還有很多,但是已經基本上實現了一個最簡單的NOCYCLE的SYS_CONNECT_BY_PATH的功能。

      

    主站蜘蛛池模板: 免费黄色福利视频| **实干一级毛片aa免费| 国产午夜无码视频免费网站| 亚洲色大成网站www永久男同 | 久9热免费精品视频在线观看| 久久亚洲高清综合| 日批视频网址免费观看| 亚洲国产高清在线| xx视频在线永久免费观看| 亚洲偷自拍另类图片二区| 国产在线98福利播放视频免费 | 亚洲乱人伦中文字幕无码| 日本大片在线看黄a∨免费| 猫咪免费人成在线网站| 2022中文字字幕久亚洲| 久久免费观看国产99精品| 亚洲婷婷综合色高清在线| 在线免费观看色片| 一级免费黄色毛片| 色拍自拍亚洲综合图区| 好爽…又高潮了免费毛片| 成人在线免费视频| 久久久亚洲精品无码| 成人性生交大片免费看无遮挡| 老司机福利在线免费观看| 亚洲国产精品成人精品无码区 | 免费看的成人yellow视频| 日本精品久久久久久久久免费| 国产亚洲精品资源在线26u| 1000部拍拍拍18勿入免费视频下载| ww亚洲ww在线观看国产| 亚洲成a人在线看天堂无码| 免费人成视频在线观看网站| 亚洲午夜理论片在线观看| 亚洲人JIZZ日本人| 啦啦啦中文在线观看电视剧免费版 | 久久精品国产大片免费观看| 亚洲精品无码专区| 久久亚洲一区二区| 免费一级成人毛片| 亚洲免费观看网站|