【发布时间】:2023-03-04 14:12:01
【问题描述】:
假设有一张关系表 (entity_id, 关系, related_id)
1, A, 2
1, A, 3
3, B, 5
1, C, null
12, C, 1
100, C, null
我需要一个能提取所有相关行的查询。 比如我查询entity_id = 1,下面的行应该被拉出来
1, A, 2
1, A, 3
3, B, 5
1, C, null
12, C, 1
其实如果我查询entity_id = 1, 2, 3, 5, or 12,结果集应该是一样的。
这与标准的经理-员工范式不同,因为没有层次结构。关系可以朝任何方向发展。
编辑 到目前为止发布的答案都没有奏效。
我想出了一个可行的解决方案。
我会将解决方案归功于能够将这个怪物清理成更优雅的东西的人。
with tab as (
-- union for reversals
select id, entity_id, r.related_id, 1 level
, cast('/' + cast(entity_id as varchar(1000)) + '/' as varchar(1000)) path
from _entity_relation r
where not exists(select null from _entity_relation r2 where r2.related_id=r.entity_id)
or r.related_id is null
union
select id, related_id, r.entity_id, 1 level
, cast('/' + cast(related_id as varchar(1000)) + '/' as varchar(1000)) path
from _entity_relation r
where not exists(select null from _entity_relation r2 where r2.related_id=r.entity_id)
or r.related_id is null
-- create recursive path
union all
select r.id, r.entity_id, r.related_id, tab.level+1
, cast(tab.path + '/' + cast(r.entity_id as varchar(100)) + '/' + '/' + cast(r.related_id as varchar(1000)) + '/' as varchar(1000)) path
from _entity_relation r
join tab
on tab.related_id = r.entity_id
)
select x.id
, x.entity_id
,pr.description as relation_description
,pt.first_name + coalesce(' ' + pt.middle_name,'') + ' ' + pt.last_name as relation_name
,CONVERT(CHAR(10), pt.birth_date, 101) as relation_birth_date
from (
select entity_id, MAX(id) as id from (
select distinct tab.id, entity_id
from tab
join(
select path
from tab
where entity_id=@in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
union
select distinct tab.id, related_id
from tab
join(
select path
from tab
where entity_id=@in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
union
select distinct tab.id, entity_id
from tab
join(
select path
from tab
where related_id=@in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
union
select distinct tab.id, related_id
from tab
join(
select path
from tab
where related_id=@in_entity_id
) p on p.path like tab.path + '%' or tab.path like p.path + '%'
) y
group by entity_id
) x
join _entity_relation pr on pr.id = x.id
join _entity pt on pt.id = x.entity_id
where x.entity_id <> @in_entity_id;
【问题讨论】:
-
如果您要查询
entity_id = 1,您的所有记录不应该都以1 开头,所以应该只返回第一条、第二条和第四条记录吗? ..好的,我明白了...您希望递归然后通过reated_id并包括这些行...但是您如何返回12,C,1?递归无法到达那里,因为它已经转过来了...... -
这是一种对等关系——这种关系可以朝任何一个方向发展
-
可以存在循环关系吗?是否允许添加
5, D, 1建立3 - 5 - 1 - 3 - 5等的关系路径? -
是的 - 这就是让它变得棘手的事情......
标签: sql sql-server recursive-query