2015-11-15 49 views
0

我有一個自我參考表:複雜的SQL查詢自我參照表

ID|NAME|PARENT_ID 
1 |P |NULL 
2 |C1 | 1 
3 |C2 | 1 
4 |C3 | 2 
5 |C4 | 4 

我想編寫一個查詢來獲得一個ID的所有兒童(無限層次) 例如: 當輸入是1,我想所有這些都是1,即

ID|NAME|PARENT_ID 
1 |P |NULL 
2 |C1 | 1 
3 |C2 | 1 
4 |C3 | 2 
5 |C4 | 4 

後代當輸入2行:

ID|NAME|PARENT_ID 
4 |C3 | 2 

請檢查這個SQL Fiddle

到目前爲止我到達這裏:

select id as productid,name,@pv:=parent_id 
from products 
join (select @pv:=1)tmp 
where [email protected] 

但只給我兩個級別的記錄,我需要的記錄無限的水平。

謝謝 腰帶

+2

這是一個分層查詢。 MySQL基本上不支持分層和遞歸查詢。要麼你需要改變你的數據結構或使用遞歸存儲過程。一個簡單的'select'語句不能做你想做的事。 –

+0

我想在你的第二個例子中你缺少'5 | C4 | 4' – Axalix

+0

類似的問題http://stackoverflow.com/questions/5291054/generating-depth-based-tree-from-hierarchical-data-in-mysql-no-ctes/5291159#5291159 – Suing

回答

1

您可以用下面的查詢實現這一目標:

select id, 
     name, 
     parent_id 
from (select * from products 
     order by parent_id, id) base, 
     (select @pv := '1') tmp 
where find_in_set(parent_id, @pv) > 0 
and  @pv := concat(@pv, ',', id) 

這裏是一個fiddle基於問題提供的一個。

@pv := '1'中指定的值應設置爲要選擇所有後代的父代的id。

如果家長有多個孩子,這也可以工作。但是,要求每個記錄parent_id < id,否則結果將不完整。

另請注意,對於非常大的數據集,此解決方案可能會變慢,因爲find_in_set操作並不是在列表中找到數字的最理想方式,當然不是按照相同順序達到大小的列表幅度與返回記錄的數量一樣。

注意:如果你想有父節點本身也包含在結果集,然後前綴與where子句中的id值的關注的上述SQL之前如下:

select id, 
     name, 
     parent_id 
from products 
where id = '1' 
union 
... 

替代1:CONNECT BY

其他一些數據庫具有特定的分層查找語法,例如Oracle數據庫上的CONNECT BY子句。 MySql不提供這樣的語法。

備選方案2:更聰明的標識符

事情變得容易得多,如果你指定包含分層信息id值。例如,你的情況,這可能是這樣的:

ID  | NAME 
1  | P 
1-1  | C1 
1-2  | C2 
1-1-1 | C3 
1-1-1-1 | C4 

那麼你的選擇是這樣的:

select id, 
     name 
from products 
where id like '1-%' 

方案3:重複自連接

如果你知道您的分層樹可以變得有多深的上限,您可以使用像這樣的標準sql

select  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  1 in (p1.parent_id, 
        p2.parent_id, 
        p3.parent_id, 
        p4.parent_id, 
        p5.parent_id) 
order  by 1, 2, 3, 4, 5, 6; 

看到這個fiddle

where條件指定要檢索的後代父母哪一方。您可以根據需要使用更多級別擴展此查詢。

+0

太棒了,謝謝 –

+0

嗨,我正在使用第一個查詢,我怎麼能得到父類別,包括孩子? –

+0

你能澄清你的意思嗎?你的意思是你希望你在'@pv:='1''中指定的值被包含在一個單獨的列中,並且所有記錄的值都相同(本例中爲'1')? – trincot