Oracle遞歸查詢(xún)樹(shù)形數(shù)據(jù)實(shí)例代碼
概述
實(shí)際生活有很多樹(shù)形結(jié)構(gòu)的數(shù)據(jù),比如公司分為多個(gè)部門(mén),部門(mén)下分為多個(gè)組,組下分為多個(gè)員工;省市縣的歸屬;頁(yè)面菜單欄等等。
如果想查詢(xún)某個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn)或者子節(jié)點(diǎn),一般通過(guò)表自身連接完成,但如果該節(jié)點(diǎn)的子節(jié)點(diǎn)還有多層結(jié)構(gòu),就需要使用遞歸調(diào)用。但如果數(shù)據(jù)量特別大,遞歸的次數(shù)指數(shù)級(jí)上升,而且查詢(xún)數(shù)據(jù)庫(kù)的次數(shù)也指數(shù)級(jí)上升,導(dǎo)致程序和數(shù)據(jù)庫(kù)壓力劇增,查詢(xún)時(shí)間特別長(zhǎng)。那數(shù)據(jù)庫(kù)有沒(méi)有遞歸查詢(xún)語(yǔ)句呢?答案是肯定的。
start with connect by prior 遞歸查詢(xún)
1、數(shù)據(jù)準(zhǔn)備
create table area_test( id number(10) not null, parent_id number(10), name varchar2(255) not null ); alter table area_test add (constraint district_pk primary key (id)); insert into area_test (ID, PARENT_ID, NAME) values (1, null, '中國(guó)'); insert into area_test (ID, PARENT_ID, NAME) values (11, 1, '河南省'); insert into area_test (ID, PARENT_ID, NAME) values (12, 1, '北京市'); insert into area_test (ID, PARENT_ID, NAME) values (111, 11, '鄭州市'); insert into area_test (ID, PARENT_ID, NAME) values (112, 11, '平頂山市'); insert into area_test (ID, PARENT_ID, NAME) values (113, 11, '洛陽(yáng)市'); insert into area_test (ID, PARENT_ID, NAME) values (114, 11, '新鄉(xiāng)市'); insert into area_test (ID, PARENT_ID, NAME) values (115, 11, '南陽(yáng)市'); insert into area_test (ID, PARENT_ID, NAME) values (121, 12, '朝陽(yáng)區(qū)'); insert into area_test (ID, PARENT_ID, NAME) values (122, 12, '昌平區(qū)'); insert into area_test (ID, PARENT_ID, NAME) values (1111, 111, '二七區(qū)'); insert into area_test (ID, PARENT_ID, NAME) values (1112, 111, '中原區(qū)'); insert into area_test (ID, PARENT_ID, NAME) values (1113, 111, '新鄭市'); insert into area_test (ID, PARENT_ID, NAME) values (1114, 111, '經(jīng)開(kāi)區(qū)'); insert into area_test (ID, PARENT_ID, NAME) values (1115, 111, '金水區(qū)'); insert into area_test (ID, PARENT_ID, NAME) values (1121, 112, '湛河區(qū)'); insert into area_test (ID, PARENT_ID, NAME) values (1122, 112, '舞鋼市'); insert into area_test (ID, PARENT_ID, NAME) values (1123, 112, '寶豐市'); insert into area_test (ID, PARENT_ID, NAME) values (11221, 1122, '尚店鎮(zhèn)');
2 start with connect by prior遞歸查詢(xún)
- start with 子句:遍歷起始條件。如果要查父結(jié)點(diǎn),這里可以用子結(jié)點(diǎn)的列,反之亦然。
- connect by 子句:連接條件。prior 跟父節(jié)點(diǎn)列parentid放在一起,就是往父結(jié)點(diǎn)方向遍歷;prior 跟子結(jié)點(diǎn)列subid放在一起,則往葉子結(jié)點(diǎn)方向遍歷。parent_id、id兩列誰(shuí)放在 “=” 前都無(wú)所謂,關(guān)鍵是prior跟誰(shuí)在一起。
- order by 子句:排序。
常用的select項(xiàng):
LEVEL:級(jí)別
connect_by_root:根節(jié)點(diǎn)
sys_connect_by_path:遞歸路徑
2.1 查詢(xún)所有子節(jié)點(diǎn)
select t.*,LEVEL from area_test t start with name ='鄭州市' connect by prior id=parent_id

其實(shí),如果單層結(jié)構(gòu),使用表自身連接也可以實(shí)現(xiàn):
select * from area_test t1,area_test t2 where t1.PARENT_ID = t2.ID and t2.name='鄭州市';

當(dāng)查詢(xún)節(jié)點(diǎn)下有多層數(shù)據(jù):
select t.*,LEVEL from area_test t start with name ='河南省' connect by prior id=parent_id

select * from area_test t1,area_test t2 where t1.PARENT_ID = t2.ID and t2.name='河南省';

如果使用自身連接,也只能查到子一級(jí)節(jié)點(diǎn)的數(shù)據(jù),需要遍歷子一級(jí)節(jié)點(diǎn),遞歸查詢(xún)每個(gè)子一級(jí)節(jié)點(diǎn)下的子節(jié)點(diǎn)。明顯麻煩很多?。?!
2.2 查詢(xún)所有父節(jié)點(diǎn)
select t.*,level from area_test t start with name ='鄭州市' connect by prior t.parent_id=t.id order by level asc;

2.3 查詢(xún)指定節(jié)點(diǎn)的根節(jié)點(diǎn)
select d.*, connect_by_root(d.id) rootid, connect_by_root(d.name) rootname from area_test d where name='二七區(qū)' start with d.parent_id IS NULL connect by prior d.id=d.parent_id

select d.*, connect_by_root(d.id) rootid, connect_by_root(d.name) rootname from area_test d start with d.parent_id IS NULL connect by prior d.id=d.parent_id

2.4 查詢(xún)下行政組織遞歸路徑
select id, parent_id, name, sys_connect_by_path(name, '->') namepath, level from area_test start with name = '平頂山市' connect by prior id = parent_id

3 with遞歸查詢(xún)
3.1 with遞歸子類(lèi)
with tmp(id, parent_id, name)
as (
select id, parent_id, name
from area_test
where name = '平頂山市'
union all
select d.id, d.parent_id, d.name
from tmp, area_test d
where tmp.id = d.parent_id
)
select * from tmp;

3.2 遞歸父類(lèi)
with tmp(id, parent_id, name) as ( select id, parent_id, name from area_test where name = '二七區(qū)' union all select d.id, d.parent_id, d.name from tmp, area_test d where tmp.parent_id = d.id ) select * from tmp;

4 MySQL 遞歸查找樹(shù)形結(jié)構(gòu)
參考文章:MySQL 遞歸查找樹(shù)形結(jié)構(gòu),這個(gè)方法太實(shí)用了
參考文章:Oracle遞歸查詢(xún)
總結(jié)
到此這篇關(guān)于Oracle遞歸查詢(xún)樹(shù)形數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Oracle遞歸查詢(xún)樹(shù)形數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Oracle客戶(hù)端與plsql查詢(xún)數(shù)據(jù)亂碼修改成中文的快速解決方法
這篇文章主要介紹了Oracle客戶(hù)端與plsql查詢(xún)數(shù)據(jù)亂碼修改成中文的快速解決方法的相關(guān)資料,需要的朋友可以參考下2016-08-08
Oracle存儲(chǔ)過(guò)程和自定義函數(shù)詳解
本篇文章主要介紹了Oracle存儲(chǔ)過(guò)程和自定義函數(shù)詳解,有需要的可以了解一下。2016-11-11
Oracle?exadata存儲(chǔ)節(jié)點(diǎn)更換內(nèi)存操作及報(bào)錯(cuò)處理方法
在進(jìn)行Oracle?Exadata巡檢時(shí),發(fā)現(xiàn)cell節(jié)點(diǎn)內(nèi)存報(bào)錯(cuò),需確認(rèn)內(nèi)存PN號(hào)及大小,并更換備件,這篇文章主要介紹了Oracle?exadata存儲(chǔ)節(jié)點(diǎn)更換內(nèi)存操作及報(bào)錯(cuò)處理的相關(guān)資料,需要的朋友可以參考下2024-10-10
Oracle單行子查詢(xún)返回多行結(jié)果的問(wèn)題解決
這篇文章主要給大家介紹了關(guān)于Oracle中單行子查詢(xún)返回多行結(jié)果的問(wèn)題解決的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用oracle具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-07-07
VS2015連接Oracle數(shù)據(jù)庫(kù)的詳細(xì)步驟
這篇文章主要介紹了VS2015連接Oracle數(shù)據(jù)庫(kù)的詳細(xì)步驟,需要的朋友可以參考下2017-10-10

