Recursive

獲取父母的所有後代

  • February 17, 2020

我有一個有兩列的表,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 如果文件不清楚,請快速搜尋可能會有所幫助:像這樣的樹遍歷是它們最常見的用途,因此如果您搜尋“遞歸公用表表達式”,您會發現很多範例。

有一些結構允許這種性質的更有效的查詢,儘管在進行更新時它們確實需要額外的工作來維護。兩個常見的選項是:

  1. 生成樹中節點(即/a/b/c)的完整路徑並將其儲存在索引列中。要搜尋所有下a您可以使用謂詞LIKE '/a/%,並為那些下b使用LIKE '/a/b/%'。對於a 及其後代,LIKE '/a%'。這對於插入很容易維護,但是當其他任何相關更改時,您需要小心更新路徑(可能通過觸發器):例如,如果b移動,您需要更新其自身及其所有後代的儲存路徑。
  2. 儲存距離圖。所以對於bstoreb,b,0b,a,1for c c,c,0,c,b,1c,a,2您的關係表中。同樣,當節點移動時,您需要做一些工作來維護這一點。此選項允許更靈活的查詢上下樹,如果你SELECT * FROM relationship_graph WHERE distance=1有你的原始樹。

如果您可以訪問副本(如果沒有,我建議您找到它!)掃描 SQL Anitpatterns 的 Naive Trees 章節。這涵蓋了足夠有用的細節,同時也可供經驗不足的人使用。

如果您無法更改結構(因為它是您幾乎無法控制的現有系統)並且無法使用遞歸 CTE,那麼您將不得不:

  • 使用儲存過程循環查找節點,直到到達底部
  • 使用一些討厭的和低效的東西,對關係表有很多連接來拉出節點。這將限於它可以尋找的深度,並且即使不需要,也會始終嘗試尋找那麼深,其中所有上述選項都可以有效地掃描無限深度。

引用自:https://dba.stackexchange.com/questions/94932