一、簡介
在oracle中start with connect by (prior) 用來對樹形結構的數據進行查詢。其中start with conditon 給出的是數據搜索范圍, connect by後面給出了遞歸查詢的條件,prior 關鍵字表示父數據,prior 條件表示子數據需要滿足父數據的什麼條件。如下
start with id= '10001' connect by prior parent_id= id and prior num = 5
表示查詢id為10001,並且遞歸查詢parent_id=id,為5的記錄。
二、實例
1、構造數據
1 -- 表結構
2 create table menu(
3 id varchar2(64) not null,
4 parent_id varchar2(64) not null,
5 name varchar2(100) not null,
6 depth number(2) not null,
7 primary key (id)
8 )
9
10 -- 初始化數據
11 -- 頂級菜單
12 insert into menu values ('100000', '0', '頂級菜單1', 1);
13 insert into menu values ('200000', '0', '頂級菜單2', 1);
14 insert into menu values ('300000', '0', '頂級菜單3', 1);
15
16 -- 父級菜單
17 -- 頂級菜單1 直接子菜單
18 insert into menu values ('110000', '100000', '菜單11', 2);
19 insert into menu values ('120000', '100000', '菜單12', 2);
20 insert into menu values ('130000', '100000', '菜單13', 2);
21 insert into menu values ('140000', '100000', '菜單14', 2);
22 -- 頂級菜單2 直接子菜單
23 insert into menu values ('210000', '200000', '菜單21', 2);
24 insert into menu values ('220000', '200000', '菜單22', 2);
25 insert into menu values ('230000', '200000', '菜單23', 2);
26 -- 頂級菜單3 直接子菜單
27 insert into menu values ('310000', '300000', '菜單31', 2);
28
29 -- 菜單13 直接子菜單
30 insert into menu values ('131000', '130000', '菜單131', 3);
31 insert into menu values ('132000', '130000', '菜單132', 3);
32 insert into menu values ('133000', '130000', '菜單133', 3);
33
34 -- 菜單132 直接子菜單
35 insert into menu values ('132100', '132000', '菜單1321', 4);
36 insert into menu values ('132200', '132000', '菜單1332', 4);
37
生成的菜單層次結構如下:
頂級菜單1
菜單11
菜單12
菜單13
菜單131
菜單132
菜單1321
菜單1322
菜單133
菜單14
頂級菜單2
菜單21
菜單22
菜單23
頂級菜單3
菜單31
2、SQL查詢
--prior放的左右位置決定了檢索是自底向上還是自頂向下. 左邊是自上而下(找子節點),右邊是自下而上(找父節點) --找父節點 select * from menu start with id='130000' connect by id = prior parent_id;

--找子節點節點 -- (子節點)id為130000的菜單,以及130000菜單下的所有直接或間接子菜單(prior 在左邊, prior、parent_id(等號右邊)在右邊) select * from menu start with id='130000' connect by prior id = parent_id ;

-- (父節點)id為1321的菜單,以及1321菜單下的所有直接或間接父菜單(prior、parent_id(等號左邊) 都在左邊) select * from menu start with id='132100' connect by prior parent_id = id; -- prior 後面跟的是(parent_id) 則是查找父節點,prior後面跟的是(id)則是查找子節點

-- 查詢所有的葉子節點 select t2.* from menu t2 where id not in(select t.parent_id from menu t) order by id;

三、性能問題
對於 start with connect by語句的執行,oracle會進行遞歸查詢,當數據量大的時候會產生性能相關問題。
--生成執行計劃 explain plan for select * from menu start with id='132100' connect by prior parent_id = id; -- 查詢執行計劃 select * from table( dbms_xplan.display);
語句執行計劃結果如下:
Plan hash value: 3563250490
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 133 | 1 (0)| 00:00:01 |
|* 1 | CONNECT BY WITH FILTERING | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID | MENU | 1 | 133 | 1 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | SYS_C0018586 | 1 | | 1 (0)| 00:00:01 |
| 4 | NESTED LOOPS | | | | | |
| 5 | CONNECT BY PUMP | | | | | |
| 6 | TABLE ACCESS BY INDEX ROWID| MENU | 1 | 133 | 1 (0)| 00:00:01 |
|* 7 | INDEX UNIQUE SCAN | SYS_C0018586 | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ID"=PRIOR "PARENT_ID")
3 - access("ID"='132100')
7 - access("ID"=PRIOR "PARENT_ID")
Note
-----
- dynamic sampling used for this statement
通過該執行計劃得知,改語句執行了7步操作,才將結果集查詢並返回。當需要查詢條件進行過濾的時候,我們可以通過查看執行計劃從而對sql進行優化。