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的查詢效率。在下面演示的功能基本上不使用這個關鍵字。

  SJFLID存儲的是上級ID,如果是頂級父節點,該SJFLID為null(得補充一句,當初的確是這樣設計的,不過現在知道,表中最好別有null記錄,這會引起全文掃描,建議改成0代替)。我們從最基本的操作,逐步列出樹查詢中常見的操作,所以查詢出來的節點以家族中的輩份作比方。1. 查找樹中的所有頂級父節點(輩份最長的人)。 假設這個樹是個目錄結構,那么第一個操作總是找出所有的頂級節點,再根據該節點找到其下屬節點。

Sql代碼
SELECT * FROM flfl WHERE sjflid IS NULL;
[sql] view plain copy
SELECT * FROM flfl WHERE sjflid IS NULL;
這是個引子,沒用到樹型查詢。

  2.查找一個節點的直屬子節點(所有兒子)。 如果查找的是直屬子類節點,也是不用用到樹型查詢的。

Sql代碼
SELECT * FROM flfl WHERE sjflid = 819459;
[sql] view plain copy
SELECT * FROM flfl WHERE sjflid = 819459;
這個可以找到ID為819459的直屬子類節點。

  3.查找一個節點的所有 直屬子節點(所有后代)。

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的節點下的所有直屬子類節點,包括子輩的和孫子輩的所有直屬節點。

  4.查找一個節點的直屬父節點(父親)。 如果查找的是節點的直屬父節點,也是不用用到樹型查詢的。

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的節點的直屬父節點,要用到同一張表的關聯了。

  5.查找一個節點的所有直屬父節點(祖宗)。

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的所有直屬父節點,打個比方就是找到一個人的父親、祖父等。但是值得注意的是這個查詢出來的結果的順序是先列出子類節點再列出父類節點,姑且認為是個倒序吧。

  上面列出兩個樹型查詢方式,第3條語句和第5條語句,這兩條語句之間的區別在于prior關鍵字的位置不同,所以決定了查詢的方式不同。 當sjflid = PRIOR ID時,數據庫會根據當前的ID迭代出sjflid與該ID相同的記錄,所以查詢的結果是迭代出了所有的子類記錄;而PRIOR ID = sjflid時,數據庫會跟據當前的sjflid來迭代出與當前的sjflid相同的id的記錄,所以查詢出來的結果就是所有的父類結果。以下是一系列針對樹結構的更深層次的查詢,這里的查詢不一定是最優的查詢方式,或許只是其中的一種實現而已。6.查詢一個節點的兄弟節點(親兄弟)。

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的節點同屬一個父節點的節點了,就好比親兄弟了。

  7.查詢與一個節點同級的節點(族兄弟)。 如果在表中設置了級別的字段,上表中的FLJB,那么在做這類查詢時會很輕松,同一級別的就是與那個節點同級的,在這里列出不使用該字段時的實現!

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語法模擬出了一張帶有級別的臨時表。

  8.查詢一個節點的父節點的的兄弟節點(伯父與叔父)。

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將查詢出來的結果進行結合起來,形成結果集。

  9.查詢一個節點的父節點的同級節點(族叔)。這個其實跟第7種情況是相同的。

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
只需要做個級別判斷就成了。

  基本上,常見的查詢在里面了,不常見的也有部分了。其中,查詢的內容都是節點的基本信息,都是數據表中的基本字段,但是在樹查詢中還有些特殊需求,是對查詢數據進行了處理的,常見的包括列出樹路徑等。補充一個概念,對于數據庫來說,根節點并不一定是在數據庫中設計的頂級節點,對于數據庫來說,根節點就是start with開始的地方。下面列出的是一些與樹相關的特殊需求。10.名稱要列出名稱全部路徑。這里常見的有兩種情況,一種是是從頂級列出,直到當前節點的名稱(或者其它屬性);一種是從當前節點列出,直到頂級節點的名稱(或其它屬性)。舉地址為例:國內的習慣是從省開始、到市、到縣、到居委會的,而國外的習慣正好相反(老師說的,還沒接過國外的郵件,誰能寄個瞅瞅 )。從頂部開始:

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一下。

  sys_connect_by_path函數就是從start with開始的地方開始遍歷,并記下其遍歷到的節點,start with開始的地方被視為根節點,將遍歷到的路徑根據函數中的分隔符,組成一個新的字符串,這個功能還是很強大的。11.列出當前節點的根節點。在前面說過,根節點就是start with開始的地方。

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函數用來列的前面,記錄的是當前節點的根節點的內容。

  12.列出當前節點是否為葉子。這個比較常見,尤其在動態目錄中,在查出的內容是否還有下級節點時,這個函數是很適用的。

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。

  至此,oracle樹型查詢基本上講完了,以上的例子中的數據是使用到做過的項目中的數據,因為里面的內容可能不好理解,所以就全部用一些新的例子來進行闡述。以上所有SQL都在本機上測試通過,也都能實現相應的功能,但是并不能保證是解決這類問題的最優方案(如第8條明顯寫成存儲過程會更好),如果誰有更好的解決方案、或者有關oracle樹查詢的任何問題,歡迎留言討論,以上的SQL有什么問題也歡迎大家留言批評。

轉載于:https://www.cnblogs.com/wayne-ivan/p/6416486.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/456417.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/456417.shtml
英文地址,請注明出處:http://en.pswp.cn/news/456417.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Mysql常用函數總結

文章目錄前言:1、日期相關函數1.1、mysql獲取未來、現在、過去的時間:DATE_SUB()、DATE_ADD()1.2、格式化日期:date_format()1.3、MySQL 日期、時間相減函數:datediff(date1,date2),…

一行Python代碼制作動態二維碼

目錄 1、普通二維碼 2、藝術二維碼 3、動態二維碼 在GitHub上發現了一個比較有意思的項目,只需要一行Python代碼就可以快捷方便生成普通二維碼、藝術二維碼(黑白/彩色)和動態GIF二維碼。 GitHub網站參加:https://github.com/sylnsfar/qrcode 用法比…

Vue常用經典開源項目匯總參考-海量

Vue常用經典開源項目匯總參考-海量 Vue是什么? Vue.js(讀音 /vju?/, 類似于 view) 是一套構建用戶界面的 漸進式框架。與其他重量級框架不同的是,Vue 采用自底向上增量開發的設計。Vue 的核心庫只關注視圖層,并且非常…

鼠標移入視頻播放,鼠標移出播放停止,恢復到原來狀態

<!doctype html> <html lang"en"> <head><meta charset"UTF-8"><title>鼠標移入視頻播放&#xff0c;鼠標移出播放停止&#xff0c;恢復到原來狀態</title><link rel"shortcut icon" href"http://f…

Pycharm常用高效技巧總結

文章目錄1、PyCharm如何自動生成函數注釋2、pycharm運行程序時在Python console窗口中運行3、Pycharm在創建py文件時,如何自動添加文件頭注釋4、Pycharm配置遠程調試5、pycharm同一目錄下無法import明明已經存在的.py文件1、PyCharm如何自動生成函數注釋 一般在函數def()行下敲…

EntityFramework中常用的數據刪除方式

最近在學EF&#xff0c;目前了解到刪除操作有三種方式&#xff0c; 第一&#xff0c;官方推薦的先查詢數據&#xff0c;再根據查詢的對象&#xff0c;刪除對象。 這是第一種&#xff0c;官方推薦 第二&#xff0c;自己創建一個對象&#xff0c;然后附加&#xff0c;然后刪除。 …

Elasticsearch的前后臺運行與停止(tar包方式)

備注&#xff1a;在生產環境中&#xff0c;往往一般用后臺來運行。jps查看。 1、ES的前臺運行 [hadoopdjt002 elasticsearch-2.4.3]$ pwd/usr/local/elasticsearch/elasticsearch-2.4.3[hadoopdjt002 elasticsearch-2.4.3]$ bin/elasticsearch 2、ES的后臺運行 [hadoopdjt002 e…

解決pycharm運行Flask指定ip、端口更改無效

后來查了一下官網文檔&#xff0c;原來Flask 1.0 版本不再支持之前的FLASK_ENV 環境變量了。 Prior to Flask 1.0 the FLASK_ENV environment variable was not supported and you needed to enable debug mode by exporting FLASK_DEBUG1. This can still be used to control…

Freeswitch總結大全

文章目錄1、Freeswitch安裝2、Freeswitch中文文檔3、Freeswitch的event socket event list的中文簡介4、freeswitch之sip協議的注冊、呼叫、掛斷流程5、Freeswitch之mod_cdr_csv6、一款第三方收費的mod_vad&#xff08;看介紹挺不錯的&#xff0c;有做語音交互的童鞋可以看下&a…

Android中SimpleAdapter的使用—自定義列表

本人初學Android&#xff0c;今天研究到Adapter這塊感覺挺有意思的&#xff0c;寫了個自定義列表進行測試 首先我們新建一個layout列表布局文件&#xff0c;具體布局可以自己設定。 下面貼上我的自定義布局文件代碼 1 <?xml version"1.0" encoding"utf-8&qu…

Module 的語法

Module 的語法 概述嚴格模式export 命令import 命令模塊的整體加載export default 命令export 與 import 的復合寫法模塊的繼承跨模塊常量import()概述 歷史上&#xff0c;JavaScript 一直沒有模塊&#xff08;module&#xff09;體系&#xff0c;無法將一個大程序拆分成互相依…

解決:SyntaxError: Non-UTF-8 code starting with '\xe6' in file

pycharm加注釋報錯SyntaxError: Non-UTF-8 code starting with \xe6 in file 處理 代碼最上面加上編碼格式 #coding:utf-8

Freeswitch之ASR(語音識別)總結大全

文章目錄1、使用Pocket Sphinx進行英文語音識別2、PocketSphinx語音識別系統語言模型的訓練和聲學模型的改進3、PocketSphinx語音識別系統的編譯、安裝和使用4、FS之play_and_detect_speech模塊5、一些開源的語音識別軟件6、某大神寫的一系列干貨7、語音識別——基于深度學習的…

linux lvm擴容

linux lvm擴容 LVM磁盤管理 一、LVM簡介... 1 二、 LVM基本術語... 2 三、 安裝LVM... 3 四、 創建和管理LVM... 4 2、 創建PV.. 6 3、 創建VG.. 7 4、 創建LV.. 9 5、LV格式化及掛載... 10 一、LVM簡介 LVM是 Logical Volume Manager(邏輯卷管理)的簡寫&#xff0c;它由Heinz …

Flask唯一URL規則--@app.route('/', endpoint='1')

Flask的URL規則基于werkzeug的路由模塊&#xff0c; 用來保證URL的唯一性。 例如帶斜線&#xff1a; app.route(/example/) def example():return ok如果訪問一個結尾不帶斜線的URL會被重定向到斜線的URL上。 &#xff08;/example&#xff09;變為(/example/) 如果不帶斜線…

智能外呼系統相關資料總結

以下是從零開始搭建智能外呼系統的過程中收集的一些資料&#xff0c;希望對你會有幫助。 1、如何從零開始搭建智能外呼系統 參考&#xff1a;https://blog.csdn.net/pA2elX78qaJTADH/article/details/81351597 2、國內外優秀呼叫中心系統簡介 參考&#xff1a;https://blog…

驅動開發之 設備讀寫方式:緩沖區方式

1. 設備對象一共同擁有三種讀寫方式&#xff1a;緩沖區方式讀寫&#xff08;Buffered方式&#xff09;&#xff1b;直接方式讀寫&#xff08;Direct方式&#xff09;。Neither方式。這三種方式的Flags分別相應DO_BUFFERED_IO,DO_DIRECT_IO,0 在buffered方式中。I/O管理器先創建…

flask開啟調試的四種模式

在app.run()中加一個參數, debugTrue就可以開啟debug模式 from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return Hello World!if __name__ __main__:app.run(debugTrue) 將app的debug屬性賦值為True 1 from flask import Flask2 3 app Flas…

Python基礎常見面試題總結

文章目錄基礎知識題看程序寫結果題編程題以下是總結的一些常見的Python基礎面試題&#xff0c;幫助大家回顧基礎知識&#xff0c;了解面試套路。會一直保持更新狀態。PS&#xff1a;加粗為需要注意的點。基礎知識題 1、深拷貝和淺拷貝的區別是什么&#xff1f; 深拷貝是將對象…

2、nginx配置文件

2、nginx配置文件user [user] [group];//運行nginx的用戶(組)&#xff08;只能在全局設置&#xff09;worker process number|auto;//允許生成的worker process數&#xff08;只能在全局設置&#xff0c;通常設置成和cpu的數量相等 &#xff09;pid file;//nginx進程的Pid存放路…