Recursive
獲取父母的所有後代
我有一個有兩列的表,
Parent
並且Child
.我需要獲取與父記錄關聯的所有後代的列表。
Source Table +----+-----------+ | Parent | Child | +----+-----------+ | a | b | | b | c | | c | d | | d | e | | e | f | | f | x | +----+-----------+ Expected Result: +----+-----------+ | Parent | Child | +----+-----------+ | a | b | // As b is the child of a, all the descendants of b | a | c | // are also descendants of a. | a | d | | a | e | | a | f | | a | x | | b | c | // As c is the child of b, all the descendants of c | b | d | // are also descendants of b. | b | e | | b | f | | b | x | | c | d | | c | e | | c | f | | c | x | | d | e | | d | f | | d | x | | e | f | | e | x | | f | x | +----+-----------+
任何想法如何獲取父母的所有後代記錄?我嘗試過使用自我加入,
T1.Child = T2.Parent
但邏輯不起作用。我正在使用不支持子句的Teiid VDB 。
Recursive WITH
您需要一個遞歸 CTE(公用表表達式):
with -- recursive -- some DBMS (e.g. Postgres) require the word "recursive" -- some others (Oracle, SQL-Server) require omitting the "recursive" -- and some (e.g. SQLite) don't bother, i.e. they accept both descendants (parent, descendant, lvl) as ( select parent, child, 1 from source union all select d.parent, s.child, d.lvl + 1 from descendants d join source s on d.descendant = s.parent ) select * from descendants order by parent, lvl, descendant ;
請參閱**SQLfiddle**。我添加的
level
不需要。它為您提供了父母和後代之間的“距離”(1 是孩子,2 是孫子女,等等)。相關 Teiid 文件的連結:(recursive) CTEs。
PS:對於甲骨文:
LEVEL
是受限制的關鍵字
如果您被這種資料結構所困擾,那麼您需要使用的是遞歸 CTE:http
://www.postgresql.org/docs/8.4/static/queries-with.html 如果文件不清楚,請快速搜尋可能會有所幫助:像這樣的樹遍歷是它們最常見的用途,因此如果您搜尋“遞歸公用表表達式”,您會發現很多範例。有一些結構允許這種性質的更有效的查詢,儘管在進行更新時它們確實需要額外的工作來維護。兩個常見的選項是:
- 生成樹中節點(即/a/b/c)的完整路徑並將其儲存在索引列中。要搜尋所有下
a
您可以使用謂詞LIKE '/a/%
,並為那些下b
使用LIKE '/a/b/%'
。對於a
及其後代,LIKE '/a%'
。這對於插入很容易維護,但是當其他任何相關更改時,您需要小心更新路徑(可能通過觸發器):例如,如果b
移動,您需要更新其自身及其所有後代的儲存路徑。- 儲存距離圖。所以對於
b
storeb,b,0
和b,a,1
forc
c,c,0
,c,b,1
在c,a,2
您的關係表中。同樣,當節點移動時,您需要做一些工作來維護這一點。此選項允許更靈活的查詢上下樹,如果你SELECT * FROM relationship_graph WHERE distance=1
有你的原始樹。如果您可以訪問副本(如果沒有,我建議您找到它!)掃描 SQL Anitpatterns 的 Naive Trees 章節。這涵蓋了足夠有用的細節,同時也可供經驗不足的人使用。
如果您無法更改結構(因為它是您幾乎無法控制的現有系統)並且無法使用遞歸 CTE,那麼您將不得不:
- 使用儲存過程循環查找節點,直到到達底部
- 使用一些討厭的和低效的東西,對關係表有很多連接來拉出節點。這將限於它可以尋找的深度,並且即使不需要,也會始終嘗試尋找那麼深,其中所有上述選項都可以有效地掃描無限深度。