Oracle树查询及相关函数
Oracle樹查詢的最重要的就是select...start with... connect by ...prior 語法了。依托于該語法,我們可以將一個表形結構的中以樹的順序列出來。在下面列述了Oracle中樹型查詢的常用查詢方式以及經常使用的與樹查詢相關的Oracle特性函數等,在這里只涉及到一張表中的樹查詢方式而不涉及多表中的關聯等。
以我做過的一個項目中的表為例,表結構如下:
Sql代碼
CREATE TABLE FLFL
(
ID NUMBER NOT NULL,
MC NVARCHAR2(20),
FLJB NUMBER,
SJFLID NUMBER
)
[sql] view plain copy
CREATE TABLE FLFL
(
ID NUMBER NOT NULL,
MC NVARCHAR2(20),
FLJB NUMBER,
SJFLID NUMBER
)
FLJB是作為樹的級別,在很多查詢中可以加快SQL的查詢效率。在下面演示的功能基本上不使用這個關鍵字。
Sql代碼
SELECT * FROM flfl WHERE sjflid IS NULL;
[sql] view plain copy
SELECT * FROM flfl WHERE sjflid IS NULL;
這是個引子,沒用到樹型查詢。
Sql代碼
SELECT * FROM flfl WHERE sjflid = 819459;
[sql] view plain copy
SELECT * FROM flfl WHERE sjflid = 819459;
這個可以找到ID為819459的直屬子類節點。
Sql代碼
SELECT * FROM flfl START WITH ID = 819459 CONNECT BY sjflid = PRIOR ID;
[sql] view plain copy
SELECT * FROM flfl START WITH ID = 819459 CONNECT BY sjflid = PRIOR ID;
這個查找的是ID為819459的節點下的所有直屬子類節點,包括子輩的和孫子輩的所有直屬節點。
Sql代碼
SELECT b.* FROM flfl a JOIN flfl b ON a.sjflid = b.ID WHERE a.ID = 6758;
[sql] view plain copy
SELECT b.* FROM flfl a JOIN flfl b ON a.sjflid = b.ID WHERE a.ID = 6758;
這個找到的是ID為6758的節點的直屬父節點,要用到同一張表的關聯了。
Sql代碼
SELECT * FROM flfl START WITH ID = 6758 CONNECT BY PRIOR sjflid = ID;
[sql] view plain copy
SELECT * FROM flfl START WITH ID = 6758 CONNECT BY PRIOR sjflid = ID;
這里查找的就是ID為6758的所有直屬父節點,打個比方就是找到一個人的父親、祖父等。但是值得注意的是這個查詢出來的結果的順序是先列出子類節點再列出父類節點,姑且認為是個倒序吧。
Sql代碼
SELECT a.*
FROM flfl a
WHERE EXISTS (SELECT *
FROM flfl b
WHERE a.sjflid = b.sjflid AND b.ID = 6757);
[sql] view plain copy
SELECT a.*
FROM flfl a
WHERE EXISTS (SELECT *
FROM flfl b
WHERE a.sjflid = b.sjflid AND b.ID = 6757);
這里查詢的就是與ID為6757的節點同屬一個父節點的節點了,就好比親兄弟了。
Sql代碼
WITH tmp AS
(SELECT a., LEVEL lev
FROM flfl a
START WITH a.sjflid IS NULL
CONNECT BY a.sjflid = PRIOR a.ID)
SELECT
FROM tmp
WHERE lev = (SELECT lev
FROM tmp
WHERE ID = 819394)
[sql] view plain copy
WITH tmp AS
(SELECT a., LEVEL lev
FROM flfl a
START WITH a.sjflid IS NULL
CONNECT BY a.sjflid = PRIOR a.ID)
SELECT
FROM tmp
WHERE lev = (SELECT lev
FROM tmp
WHERE ID = 819394)
這里使用兩個技巧,一個是使用了LEVEL來標識每個節點在表中的級別,還有就是使用with語法模擬出了一張帶有級別的臨時表。
Sql代碼
WITH tmp AS
(SELECT flfl., LEVEL lev
FROM flfl
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID)
SELECT b.
FROM tmp b,
(SELECT *
FROM tmp
WHERE ID = 7004 AND lev = 2) a
WHERE b.lev = 1
UNION ALL
SELECT *
FROM tmp
WHERE sjflid = (SELECT DISTINCT x.ID
FROM tmp x,
tmp y,
(SELECT *
FROM tmp
WHERE ID = 7004 AND lev > 2) z
WHERE y.ID = z.sjflid AND x.ID = y.sjflid);
[sql] view plain copy
WITH tmp AS
(SELECT flfl., LEVEL lev
FROM flfl
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID)
SELECT b.
FROM tmp b,
(SELECT *
FROM tmp
WHERE ID = 7004 AND lev = 2) a
WHERE b.lev = 1
UNION ALL
SELECT *
FROM tmp
WHERE sjflid = (SELECT DISTINCT x.ID
FROM tmp x,
tmp y,
(SELECT *
FROM tmp
WHERE ID = 7004 AND lev > 2) z
WHERE y.ID = z.sjflid AND x.ID = y.sjflid);
這里查詢分成以下幾步。首先,將第7個一樣,將全表都使用臨時表加上級別;其次,根據級別來判斷有幾種類型,以上文中舉的例子來說,有三種情況:(1)當前節點為頂級節點,即查詢出來的lev值為1,那么它沒有上級節點,不予考慮。(2)當前節點為2級節點,查詢出來的lev值為2,那么就只要保證lev級別為1的就是其上級節點的兄弟節點。(3)其它情況就是3以及以上級別,那么就要選查詢出來其上級的上級節點(祖父),再來判斷祖父的下級節點都是屬于該節點的上級節點的兄弟節點。 最后,就是使用UNION將查詢出來的結果進行結合起來,形成結果集。
Sql代碼
WITH tmp AS
(SELECT a., LEVEL lev
FROM flfl a
START WITH a.sjflid IS NULL
CONNECT BY a.sjflid = PRIOR a.ID)
SELECT
FROM tmp
WHERE lev = (SELECT lev
FROM tmp
WHERE ID = 819394) - 1
[sql] view plain copy
WITH tmp AS
(SELECT a., LEVEL lev
FROM flfl a
START WITH a.sjflid IS NULL
CONNECT BY a.sjflid = PRIOR a.ID)
SELECT
FROM tmp
WHERE lev = (SELECT lev
FROM tmp
WHERE ID = 819394) - 1
只需要做個級別判斷就成了。
Sql代碼
SELECT SYS_CONNECT_BY_PATH (mc, '/')
FROM flfl
WHERE ID = 6498
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;
[sql] view plain copy
SELECT SYS_CONNECT_BY_PATH (mc, '/')
FROM flfl
WHERE ID = 6498
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;
從當前節點開始:
Sql代碼
SELECT SYS_CONNECT_BY_PATH (mc, '/')
FROM flfl
START WITH ID = 6498
CONNECT BY PRIOR sjflid = ID;
[sql] view plain copy
SELECT SYS_CONNECT_BY_PATH (mc, '/')
FROM flfl
START WITH ID = 6498
CONNECT BY PRIOR sjflid = ID;
在這里我又不得不放個牢騷了。Oracle只提供了一個sys_connect_by_path函數,卻忘了字符串的連接的順序。在上面的例子中,第一個SQL是從根節點開始遍歷,而第二個SQL是直接找到當前節點,從效率上來說已經是千差萬別,更關鍵的是第一個SQL只能選擇一個節點,而第二個SQL卻是遍歷出了一顆樹來。再次PS一下。
Sql代碼
SELECT CONNECT_BY_ROOT mc, flfl.*
FROM flfl
START WITH ID = 6498
CONNECT BY PRIOR sjflid = ID;
[sql] view plain copy
SELECT CONNECT_BY_ROOT mc, flfl.*
FROM flfl
START WITH ID = 6498
CONNECT BY PRIOR sjflid = ID;
connect_by_root函數用來列的前面,記錄的是當前節點的根節點的內容。
Sql代碼
SELECT CONNECT_BY_ISLEAF, flfl.*
FROM flfl
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;
[sql] view plain copy
SELECT CONNECT_BY_ISLEAF, flfl.*
FROM flfl
START WITH sjflid IS NULL
CONNECT BY sjflid = PRIOR ID;
connect_by_isleaf函數用來判斷當前節點是否包含下級節點,如果包含的話,說明不是葉子節點,這里返回0;反之,如果不包含下級節點,這里返回1。
轉載于:https://www.cnblogs.com/wayne-ivan/p/6416486.html
總結
以上是生活随笔為你收集整理的Oracle树查询及相关函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jquery ajax參数加点号状态20
- 下一篇: 移动平台自动化测试:appium(一)