for example:
create
table products(
id int,
name varchar(100),
parent_id int
);insert
into products values
(15, 'category15', 0), -- not a descendant of
19(16, 'category16', 15), -- not a descendant of
19(19, 'category19', 0),
(20, 'category20', 19), -- level
1(21, 'category21', 20), -- level
2(22, 'category22', 21), -- level
3(23, 'category23', 19), -- level
1(24, 'category24', 21), -- level
3(25, 'category25', 22), -- level
4(26, 'category26', 22), -- level
4(27, 'category26', 25), -- level
5(30, 'category21', 16);
-- not a descendant of 19
solution:
select id,
name,
parent_id
from (select * from products
order
by parent_id, id) products_sorted,
(select @pv := '19') initialisation
where find_in_set(parent_id, @pv)
and length(@pv := concat(@pv, ',', id))
result:
name parent_id
20 category20 19
23 category23 19
21 category21 20
22 category22 21
24 category24 21
25 category25 22
26 category26 22
27 category26 25
指定的值@pv := 『19』應該設定為id要選擇所有子項的父id。
如果父節點有多個子節點,這一樣有效。但是,要求每條記錄都滿足條件parent_id < id,否則結果不準確。
該查詢使用特定的mysql語法:在執行期間分配和修改變數。對執行順序做了一些假設:
from項首先被執行。所以這就是@pv初始化的地方。
where子句按照從from別名中檢索的順序執行每條記錄。所以這是乙個條件被放置的地方,只包括父母已經被識別為在後代樹中的記錄(主要父母的所有後代都被逐步新增到@pv)。
本節中的條件按where順序進行評估,一旦總體結果確定,評估就會中斷。因此,第二個條件必須排在第二位,因為它將它新增id到父列表中,並且只有在id傳遞第乙個條件時才會發生。length函式僅用於確保此條件始終為真,即使該pv字串會產生虛假值。
所以,人們可能會發現這些假設風險太高而無法依賴 - 它們沒有檔案保證,即使它一貫地工作,當您將此查詢用作檢視或子檢視時,執行順序在理論上可能仍會發生變化。
另外注意,如果是非常大的資料,這個解決方案可能會變慢,因為find_in_set操作並不是在列表中找到數字的最理想方式,當然不是在與數量相同的數量級達到大小的列表中記錄返回。
方案1: with recursive,connect by
現在越來越多的資料庫都支援以下標準:1999 iso標準with [recursive]語法的遞迴查詢(如postgres的8.4+,sql server的2005+,db2,甲骨文11gr2的+,sqlite的3.8.4+,火鳥2.1+,h2,的hypersql 2.1.0+,teradata的,mariadb 10.2.2+)。從版本8.0開始,mysql也將支援它。使用該語法,查詢如下所示:
( select id,
name,
parent_id
from products
where parent_id = 19
union all
select p.id,
p.name,
p.parent_id
from products p
inner join cte
onp.parent_id = cte.id
)select * from cte;
一些資料庫有用於分層查詢的替代非標準語法,例如connect byoracle資料庫上可用的子句。db2也支援這種替代語法。
mysql 5.7不支援。如果你的資料庫版本支援這種語法時,那最好了。如果不支援,請考慮以下選擇。
方案2:id標示路徑
如果id包含路徑層次結構資訊,那就很好處理。例如,在你的情況下,這可能看
id | name
19| category1
19/1
| category2
19/1/1
| category3
19/1/1/1
| category4 --
select id,
name
from products
where id like
'19/%'
方案3:同表連線
如果知道層次結構樹有幾層,可以試試下面的sql:
select p6.parent_id as parent6_id,
p5.parent_id as parent5_id,
p4.parent_id as parent4_id,
p3.parent_id as parent3_id,
p2.parent_id as parent2_id,
p1.parent_id as parent_id,
p1.id as product_id,
p1.name
from products p1
left
join products p2 on p2.id = p1.parent_id
left
join products p3 on p3.id = p2.parent_id
left
join products p4 on p4.id = p3.parent_id
left
join products p5 on p5.id = p4.parent_id
left
join products p6 on p6.id = p5.parent_id
where
19in (p1.parent_id,
p2.parent_id,
p3.parent_id,
p4.parent_id,
p5.parent_id,
p6.parent_id)
order
by1, 2, 3, 4, 5, 6, 7;
from: 谷歌翻譯 PostgreSQL遞迴查詢實現樹狀結構查詢
在postgresql的使用過程中發現了乙個很有意思的功能,就是對於需要類似於樹狀結構的結果可以使用遞迴查詢實現。比如說我們常用的公司部門這種資料結構,一般我們設計表結構的時候都是類似下面的sql,其中parent id為null時表示頂級節點,否則表示上級節點id。create table dep...
樹狀遞迴查詢
樹狀等級查詢 所有資料 從mysql裡面輸出的全部是字串型別 list array array cat id 8 cat name 分類fff sort order 30 parent id 1 array cat id 1 cat name 分類aaa sort order 50 parent i...
Oracle 遞迴遍歷樹狀結構
connect by prior 是結構化查詢中用到的,其基本語法是 select from tablename start with 條件1 connect by prior 條件2 where 條件3 從root往樹末梢遞迴 sql select from tablename start wit...