比方說,我有一個叫人與列的表:遞歸查詢列
id, name, parent_id
,讓我們說我有一些像這樣的數據:
1, Bob, null
2, Mary, 1
3, Tim, 1
4, Sally, 3
所以鮑勃有兩個孩子:瑪麗和蒂姆。 和蒂姆有1個孩子:莎莉(祖父母是鮑勃)
什麼是寫一個JPA查詢的最簡單方法,以便我可以找到鮑勃的所有後代? (即結果將返回瑪麗,蒂姆和莎莉)
比方說,我有一個叫人與列的表:遞歸查詢列
id, name, parent_id
,讓我們說我有一些像這樣的數據:
1, Bob, null
2, Mary, 1
3, Tim, 1
4, Sally, 3
所以鮑勃有兩個孩子:瑪麗和蒂姆。 和蒂姆有1個孩子:莎莉(祖父母是鮑勃)
什麼是寫一個JPA查詢的最簡單方法,以便我可以找到鮑勃的所有後代? (即結果將返回瑪麗,蒂姆和莎莉)
我不認爲你可以用普通的JPA做到這一點。
但是,如果你可以修改你的表像這樣
id, name, parent_path(string)
您的信息就會看起來像這樣
1, Bob, null
2, Mary, 1
3, Tim, 1
4, Sally, 1/3
5, John, 1/3/4
6, Huge, 1/3/4/5
,那麼你可以查詢使用類似條款的所有後代。 例如:
select p from Person p where p.parentPath like '1/%'
這裏1 - 是parentPath + ENTITYID,所以對於鮑勃喜歡條款看起來像
like '1/%'
因爲Bob的parentPath爲空和Bob的ID爲1
而對於Sally的查詢將如下所示
select p from Person p where p.parentPath like '1/3/4/%'
因爲Sally的parentPath是「1/3」和Sally的id是4
,如果你要添加一個新的孩子,你只需要它的設置PARENT_PATH到
parent.parentPath + '/' + parent.id
大多數現代DBMS支持使用遞歸公用表表達式層次查詢。如果你可以通過一個簡單的SQL語句的JPA層,這可以很容易地類似於以下一條語句完成:
WITH RECURSIVE people_tree (id, name, parent) as
(
SELECT id, name, parent_id
FROM people
WHERE parent name = 'Bob'
UNION ALL
SELECT p2.id, p2.name, p2.parent_id
FROM people p2
INNER JOIN people_tree ON people_tree.id = p2.parent_id
)
SELECT *
FROM people_tree
ORDER BY name;
我用嵌套集合解決同樣的問題。請參閱我的問題&回答:How to show tree-view replies to message? Java & Hibernate
我相信這是查詢關係數據庫中的分層數據的最佳解決方案。
在SQL Server 2008中的以下查詢的工作來獲取級別的每個元素是,假設你的表名爲Hierarchical_Test1,幷包含字段「ID,姓名,PARENT_ID」:
with family_tree (parent_id, id, name, level) AS
(
-- Anchor member definition
select f.parent_id, f.id, f.name, 0 as level
from dbo.Hierarchical_Test1 f
where f.parent_id=0
union all
-- Recursive member definition
select f2.parent_id, f2.id, f2.name, level + 1
from dbo.Hierarchical_Test1 as f2
inner join family_tree as f3
on f2.parent_id = f3.id
)
-- Statement that executes the CTE
select parent_id, id, name, level
from family_tree
而這一次得到你所有的元素的祖先:
with family_tree (parent_id, id, name, level, parent_path) AS
(
-- Anchor member definition
select f.parent_id, f.id, f.name, 0 as level,
CAST('/' as varchar(255)) as parent_path
from dbo.Hierarchical_Test1 f
where f.parent_id=0
union all
-- Recursive member definition
select f2.parent_id, f2.id, f2.name, level + 1,
CAST(
CAST('/' as varchar(255))
+ CAST(f2.parent_id as varchar(255))
+ CAST(f3.parent_path as varchar(255))
as varchar(255))
from dbo.Hierarchical_Test1 as f2
inner join family_tree as f3
on f2.parent_id = f3.id
)
-- Statement that executes the CTE
select parent_id, id, name, level, parent_path
from family_tree
路徑的想法一般都很好,但你需要小心「like」; 「像'1/3/4%'這樣的parentPath會拿起'1/3/42'以及'1/3/4/2'。通常我通過做'1/3/4 /%'。 – wrschneider
感謝您關注此事。 – szhem