1. 程式人生 > 資料庫 >Oracle遞迴樹形結構查詢功能

Oracle遞迴樹形結構查詢功能

oracle樹狀結構查詢即層次遞迴查詢,是sql語句經常用到的,在實際開發中組織結構實現及其層次化實現功能也是經常遇到的。

概要:樹狀結構通常由根節點、父節點、子節點和葉節點組成,簡單來說,一張表中存在兩個欄位,dept_id,par_dept_id,那麼通過找到每一條記錄的父級id即可形成一個樹狀結構,也就是par_dept_id(子)=dept_id(父),通俗的說就是這條記錄的par_dept_id是另外一條記錄也就是父級的dept_id,其樹狀結構層級查詢的基本語法是:

  SELECT [LEVEL],*
  FEOM table_name
  START WITH 條件1
  CONNECT BY PRIOR 條件2
  WHERE 條件3
  ORDER BY 排序欄位

  說明:LEVEL---偽列,用於表示樹的層次

     條件1---根節點的限定條件,當然也可以放寬許可權,以獲得多個根節點,也就是獲取多個樹

     條件2---連線條件,目的就是給出父子之間的關係是什麼,根據這個關係進行遞迴查詢

     條件3---過濾條件,對所有返回的記錄進行過濾。

     排序欄位---對所有返回記錄進行排序

  對prior說明:要的時候有兩種寫法:connect by prior dept_id=par_dept_id connect by dept_id=prior par_dept_id,前一種寫法表示採用自上而下的搜尋方式(先找父節點然後找子節點),後一種寫法表示採用自下而上的搜尋方式(先找葉子節點然後找父節點)。

  樹狀結構層次化查詢需要對樹結構的每一個節點進行訪問並且不能重複,其訪問步驟為:

  大致意思就是掃描整個樹結構的過程即遍歷樹的過程,其用語言描述就是:

  步驟一:從根節點開始;

  步驟二:訪問該節點;

  步驟三:判斷該節點有無未被訪問的子節點,若有,則轉向它最左側的未被訪問的子節,並執行第二步,否則執行第四步;

  步驟四:若該節點為根節點,則訪問完畢,否則執行第五步;

  步驟五:返回到該節點的父節點,並執行第三步驟。

  除此之外,sys_connect_by_path函式是和connect by 一起使用的,在實戰中具體帶目的具體介紹!

實戰:最近做專案的組織結構,對於部門的各級層次顯示,由於這部分掌握不牢固,用最笨的like模糊查詢解決了,雖然功能實現了,但是問題很多,如擴充套件性不好,稍微改下需求就要進行大改,不滿意最後對其進行了優化。在開發中能用資料庫解決的就不要用java去解決,這也是我一直保持的想法並堅持著。

建立表:

create table SYS_DEPT 
 (
 dept_id   VARCHAR2(32) not null,dept_name  VARCHAR2(128),dept_code  VARCHAR2(32),par_dept_id  VARCHAR2(32),dept_leader  VARCHAR2(32),dept_desc  VARCHAR2(256),create_time  CHAR(19),org_id   VARCHAR2(32),dept_type  VARCHAR2(1),order_id  NUMBER,state   CHAR(1) default '1',bqq_dept_id  VARCHAR2(128),bqq_par_dept_id VARCHAR2(128)
 )
 -- Add comments to the table
 comment on table SYS_DEPT
 is '部門資訊,和單位多對一';
 -- Add comments to the columns
 comment on column SYS_DEPT.dept_id
 is '主鍵';
 comment on column SYS_DEPT.dept_name
 is '名稱';
 comment on column SYS_DEPT.dept_code
 is '編碼,用於遞迴';
 comment on column SYS_DEPT.par_dept_id
 is '父級部門ID';
 comment on column SYS_DEPT.dept_leader
 is '部門領導ID';
 comment on column SYS_DEPT.dept_desc
 is '部門描述';
 comment on column SYS_DEPT.create_time
 is 'yyyy-mm-dd HHMMSS';
 comment on column SYS_DEPT.org_id
 is '單位ID';
 comment on column SYS_DEPT.dept_type
 is '1:正式部門;2:虛擬部門(用於通訊錄展示)';
 comment on column SYS_DEPT.order_id
 is '排序欄位';
 comment on column SYS_DEPT.state
 is '0:無效;1:有效';
 comment on column SYS_DEPT.bqq_dept_id
 is '企業qqdeptid';
 comment on column SYS_DEPT.bqq_par_dept_id
 is '企業qq父類deptid';

  插入測試資料:

insert into SYS_DEPT (DEPT_ID,DEPT_NAME,DEPT_CODE,PAR_DEPT_ID,DEPT_LEADER,DEPT_DESC,CREATE_TIME,ORG_ID,DEPT_TYPE,ORDER_ID,STATE,BQQ_DEPT_ID,BQQ_PAR_DEPT_ID)
values ('40288ac45a3c1e8b015a3c28b4ae01d6','客運部','110','-1',null,'2017-02-14 182625','402881e54c40d74d014c40d8407a0016','1',29,null);
insert into SYS_DEPT (DEPT_ID,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b60f98a1d59b3','綜合室','110001','40288ac45a3c1e8b015a3c28b4ae01d6','2017-04-12 150338',63,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6134d9ff2946','生產排程','110001001','4028e4d35b5ca4ee015b60f98a1d59b3','2017-04-12 160825',135,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b60f9fae95a44','站務中心','110002','2017-04-12 150407',64,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613562be2a08','東崗站','110002001','4028e4d35b5ca4ee015b60f9fae95a44','2017-04-12 160900',136,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6135f9de2aca','焦家灣站','110002002','2017-04-12 160939',137,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6136a3e22bb2','拱星墩站','110002003','2017-04-12 161022',138,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613723bb2c5f','省氣象局站','110002004','2017-04-12 161055',139,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6137a5772d06','五里鋪站','110002005','2017-04-12 161128',140,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6137e4e72d57','蘭州大學站','110002006','2017-04-12 161144',141,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613840112dd0','東方紅廣場站','110002007','2017-04-12 161208',142,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6138765c2e12','省政府站','110002008','2017-04-12 161221',143,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6138b84b2e68','西關站','110002009','2017-04-12 161238',145,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6139390e2f06','文化宮站','110002010','2017-04-12 161311',146,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613980a82f61','小西湖站','110002011','2017-04-12 161330',147,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b6139c1dc2fb4','七里河站','110002012','2017-04-12 161346',148,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613a24853047','西站十字站','110002013','2017-04-12 161412',149,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613a81f030ce','蘭州西站北廣場站','110002014','2017-04-12 161436',150,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613ad627313d','土門墩站','110002015','2017-04-12 161457',151,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613b394c31c6','馬灘站','110002016','2017-04-12 161522',152,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613b9051325e','蘭州海關站','110002017','2017-04-12 161545',153,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613c286b332e','蘭州城市學院(省科技館)站','110002018','2017-04-12 161624',154,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613c806933a3','深安大橋南站','110002019','2017-04-12 161646',155,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613cdf98342c','陳官營站','110002020','2017-04-12 161711',157,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b60fa3e2f5a94','乘務中心','110003','2017-04-12 150424',65,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613d738d34f4','陳官營車場組','110003001','4028e4d35b5ca4ee015b60fa3e2f5a94','2017-04-12 161748',158,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613defed359e','東崗車場組','110003002','2017-04-12 161820',159,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613e42ae3612','第一車隊','110003003','2017-04-12 161841',161,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613e7a50366c','第二車隊','110003004','2017-04-12 161856',162,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613ebc8e36c1','第三車隊','110003005','2017-04-12 161913',163,BQQ_PAR_DEPT_ID)
values ('4028e4d35b5ca4ee015b613eff483729','第四車隊','110003006','2017-04-12 161930',164,null);

  在這張表中有三個欄位:dept_id 部門主鍵id;dept_name 部門名稱;dept_code 部門編碼;par_dept_id 父級部門id(首級部門為 -1); 當前節點遍歷子節點(遍歷當前部門下所有子部門包括本身)

select t.dept_id,t.dept_name,t.dept_code,t.par_dept_id,level 
 from SYS_DEPT t 
 start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6' 
 connect by prior t.dept_id = t.par_dept_id 
 order by level,t.dept_code 

結果:

dept_id=40288ac45a3c1e8b015a3c28b4ae01d6 是客運部主鍵,對其下的所有子部門進行遍歷,同時用 order by level,dept_code 進行排序 以便達到實際生活中想要的資料;共31條資料,部分資料如圖所示:

但是:

  有問題啊,如果你想在上面的資料中獲取層級在2也就是level=2的所有部門,發現剛開始的時候介紹的語言不起作用?並且會報ORA-00933:sql命令未正確結束,why?

這個我暫時也沒有得到研究出理論知識,但是改變下where level='2'的位置發現才會可以的。錯誤的和正確的sql我們對比一下,以後會用就行,要是路過的大神知道為什麼,還請告知下,萬分感謝!

錯誤sql:

select t.dept_id,level 
 from SYS_DEPT t 
 start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6' 
 connect by prior t.dept_id = t.par_dept_id 
 where level = '2' 
 order by level,t.dept_code 

正確sql:

select t.dept_id,level 
 from SYS_DEPT t 
 where level = '2' 
 start with t.dept_id = '40288ac45a3c1e8b015a3c28b4ae01d6' 
 connect by prior t.dept_id = t.par_dept_id 
 order by level,t.dept_code 


當然了,這個對其他形式的where過濾所有返回記錄沒有影響的,這個只是一個例外!

sys_connect_by_path函式求父節點到子節點路徑

簡單介紹下,在oracle中sys_connect_by_path與connect by 一起使用,也就是先要有或建立一棵樹,否則無用還會報錯。它的主要作用體現在path上即路徑,是可以吧一個父節點下的所有節點通過某個字元區分,然後連結在一個列中顯示。

sys_connect_by_path(column,clear),其中column是字元型或能自動轉換成字元型的列名,它的主要目的就是將父節點到當前節點的“path”按照指定的模式出現,char可以是單字元也可以是多字元,但不能使用列值中包含的字元,而且這個引數必須是常量,且不允許使用繫結變數,clear不要用逗號。
文字容易讓人疲勞,放圖和程式碼吧

select sys_connect_by_path(t.dept_name,'-->'),t.dept_id,t.dept_code 

結果:

下面以最簡單的情況進行示例說明:

SELECT t.f_id,SYS_CONNECT_BY_PATH(t.f_id,'\') AS con_code,SYS_CONNECT_BY_PATH(t.f_name,'\') AS con_name
FROM 表名 t
START WITH t.f_pid IS NULL 
CONNECT BY PRIOR t.f_id = t.f_pid;

說明:其中的f_id為標識碼,f_pid為父節點標識碼,f_name為名稱

總結

以上所述是小編給大家介紹的Oracle遞迴樹形結構查詢功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!