oracle中的樹狀查詢
oracle中的樹狀查詢
工作中經常會遇到將數據庫中的數據以樹的形式展現的需求。以下我們來看一下該需求在Oracle中如何實現。
首先我們需要有一個樹形的表結構(當然有時候會出現表結構不是典型的樹形結構,而是多表存儲,需要根據多表連接查詢生成樹)
一、樹型表結構:
節點ID 上級ID 節點名稱
二、用法:
select 節點ID,節點名稱,level
from 表名
connect by prior 節點ID=上級節點ID
start with 上級節點ID=節點值
說明:
1、常見的樹形結構為公司組織機構、地區……
2、求節點ID以上的結構,或以下的結構,將“節點ID=上級節點ID”左右順序換一下即可。
3、Level為Oracle的特殊字段,表示“層”的意思。當前節點ID的下一層節點為“1”。
測試SQL: 1,建立表結構
CREATE TABLE "TEAMB0"."MATBOM"
( "FACT_NO" CHAR(4) NOT NULL ENABLE,
"CARRY_MK" CHAR(1) NOT NULL ENABLE,
"MAIN_MAT_NO" CHAR(20) NOT NULL ENABLE,
"SUB_MAT_NO" CHAR(20) NOT NULL ENABLE,
"PRD_CODE" CHAR(1) NOT NULL ENABLE,
"PRD_RATE" NUMBER(8,5) NOT NULL ENABLE,
"MODIFY_USER" VARCHAR2(60),
"MODIFY_DATE" CHAR(14),
"BLOC_MK" CHAR(1)
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USER_DATA"
插入數據:
Insert into MATBOM (FACT_NO,CARRY_MK,MAIN_MAT_NO,SUB_MAT_NO,PRD_CODE,PRD_RATE,MODIFY_USER,MODIFY_DATE,BLOC_MK) values (‘216M‘,‘N‘,‘A020408G02A059 ‘,‘A020408G01A059 ‘,‘3‘,1,null,null,null);
Insert into MATBOM (FACT_NO,CARRY_MK,MAIN_MAT_NO,SUB_MAT_NO,PRD_CODE,PRD_RATE,MODIFY_USER,MODIFY_DATE,BLOC_MK) values (‘216M‘,‘N‘,‘A020408G15A059 ‘,‘A020408G01A059 ‘,‘3‘,1,null,null,null);
Insert into MATBOM (FACT_NO,CARRY_MK,MAIN_MAT_NO,SUB_MAT_NO,PRD_CODE,PRD_RATE,MODIFY_USER,MODIFY_DATE,BLOC_MK) values (‘216M‘,‘N‘,‘A020408G18A059 ‘,‘A020408G01A059 ‘,‘5‘,1,‘S6042382‘,‘20081020133712‘,null);
Insert into MATBOM (FACT_NO,CARRY_MK,MAIN_MAT_NO,SUB_MAT_NO,PRD_CODE,PRD_RATE,MODIFY_USER,MODIFY_DATE,BLOC_MK) values (‘216M‘,‘N‘,‘N090823G09A059 ‘,‘A020408G01A059 ‘,‘1‘,1,‘S6042382‘,‘20081208150154‘,null);
Insert into MATBOM (FACT_NO,CARRY_MK,MAIN_MAT_NO,SUB_MAT_NO,PRD_CODE,PRD_RATE,MODIFY_USER,MODIFY_DATE,BLOC_MK) values (‘216M‘,‘N‘,‘A020408G01A059 ‘,‘A020408G01A059-1 ‘,‘3‘,1,null,null,null);
INSERT INTO MATBOM (FACT_NO,CARRY_MK,MAIN_MAT_NO,SUB_MAT_NO,PRD_CODE,PRD_RATE,MODIFY_USER,MODIFY_DATE,BLOC_MK) VALUES (‘216M‘,‘N‘,‘A020408G01A059 ‘,‘A020408G01A059-2 ‘,‘3‘,1,NULL,NULL,NULL);
INSERT INTO MATBOM (FACT_NO,CARRY_MK,MAIN_MAT_NO,SUB_MAT_NO,PRD_CODE,PRD_RATE,MODIFY_USER,MODIFY_DATE,BLOC_MK)
VALUES (‘216M‘,‘N‘,‘T1-A020408G02A059 ‘,‘A020408G02A059 ‘,‘3‘,1,NULL,NULL,NULL);
SQL查詢
--prior放的左右位置決定了檢索是自底向上還是自頂向下. 左邊是自上而下(找子節點),右邊是自下而上(找父節點) --找父節點
SELECT MAIN_MAT_NO,sub_mat_no,level
FROM MATBOM
CONNECT BY SUB_MAT_NO = PRIOR MAIN_MAT_NO
START WITH SUB_MAT_NO = ‘A020408G01A059 ‘;
;or
SELECT MAIN_MAT_NO,sub_mat_no,level
FROM MATBOM
START WITH SUB_MAT_NO = ‘A020408G01A059 ‘
CONNECT BY SUB_MAT_NO = PRIOR MAIN_MAT_NO;
;
--找子節點節點 -- (子節點)SUB_MAT_NO 為A020408G01A059 的子材料,以及A020408G01A059 子材料下的所有直接或間接子材料(prior 在左邊, prior、MAIN_MAT_NO(等號右邊)在右邊)
SELECT MAIN_MAT_NO,sub_mat_no,level
FROM MATBOM
START WITH SUB_MAT_NO = ‘A020408G01A059‘
CONNECT BY PRIOR SUB_MAT_NO = MAIN_MAT_NO;
三、性能問題
對於 start with connect by語句的執行,oracle會進行遞歸查詢,當數據量大的時候會產生性能相關問題。
--生成執行計劃
EXPLAIN PLAN FOR SELECT * FROM MATBOM START WITH SUB_MAT_NO = ‘A020408G01A059‘ CONNECT BY SUB_MAT_NO = PRIOR MAIN_MAT_NO;
-- 查詢執行計劃
select * from table( dbms_xplan.display);
語句執行計劃結果如下:
Plan hash value: 1868394721
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 7 | 840 | 3 (0)| 00:00:01 |
|* 1 | CONNECT BY NO FILTERING WITH START-WITH| | | | | |
| 2 | TABLE ACCESS FULL | MATBOM | 7 | 840 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("SUB_MAT_NO"=PRIOR "MAIN_MAT_NO")
filter("SUB_MAT_NO"=‘A020408G01A059‘)
Note
-----
- dynamic sampling used for this statement
通過該執行計劃得知,改語句執行了7步操作,才將結果集查詢並返回。當需要查詢條件進行過濾的時候,我們可以通過查看執行計劃從而對sql進行優化。
oracle中的樹狀查詢