2011-11-13 99 views
2

比方说,我有一个叫人与列的表:递归查询列

id, name, parent_id 

,让我们说我有一些像这样的数据:

1, Bob, null 
2, Mary, 1 
3, Tim, 1 
4, Sally, 3 

所以鲍勃有两个孩子:玛丽和蒂姆。 和蒂姆有1个孩子:莎莉(祖父母是鲍勃)

什么是写一个JPA查询的最简单方法,以便我可以找到鲍勃的所有后代? (即结果将返回玛丽,蒂姆和莎莉)

回答

3

我不认为你可以用普通的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 
+1

路径的想法一般都很好,但你需要小心“like”; “像'1/3/4%'这样的parentPath会拿起'1/3/42'以及'1/3/4/2'。通常我通过做'1/3/4 /%'。 – wrschneider

+0

感谢您关注此事。 – szhem

2

大多数现代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; 
0

在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