假设有一张关系表 (entity_id,relationship,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或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;
答案 0 :(得分:1)
我首先创建了一个包含双向关系的表,然后创建了一个递归CTE,使用这两种方式结果构建了具有祖先路径的整个层次结构......
with both as
(
select *, 0 as rev
from t
where related_id is not null
union
select *, 1
from t
),
recurs as
(
select *, cast('/' as varchar(100)) as anc
from both
where entity_id is null
union all
select b.*, cast(re.anc + cast(b.entity_id as varchar) + '/' as varchar(100))
from both b
join recurs re
on (re.related_id = b.entity_id)
where charindex('/'+cast(isnull(b.entity_id,'') as varchar)+'/', re.anc) = 0
)
select *
/*
THIS ONE SHOULD BE USED TO RETURN TO ORIGINAL
case when is_reverse = 1 then related_id else entity_id end as entity_id,
relationship,
case when is_reverse = 0 then related_id else entity_id end as related_id
*/
from recurs
where related_id = xXx or
charindex('/'+cast(xXx as varchar)+'/', anc) != 0
将xXx
替换为实际值。
此查询假定根元素是entity_id = null
的元素,因此它从那里构建整个递归。如果情况并非如此,则必须相应地进行更改。
我添加了循环检查,循环是1,2,3,4,5, 1 或1,2,3,4,5, 3 。 ..所以全部或部分循环。两者都有效。
答案 1 :(得分:1)
为了完成你的任务,你要小心你的数据,你必须避免循环引用。可以优化以下查询,但确保它可以正常工作
;with tab as (
select entity_id, relationship, related_id, 1 level, cast('/' + cast(entity_id as varchar(1000)) as varchar(1000)) path
from #r r
where not exists(select null from #r r2 where r2.related_id=r.entity_id)
or r.related_id is null
union all
select r.entity_id, r.relationship, r.related_id, tab.level+1, cast(tab.path + '/' + cast(r.entity_id as varchar(100)) as varchar(1000)) path
from #r r
join tab
on tab.related_id = r.entity_id
)
select distinct tab.*
from tab
join(
select path
from tab
where entity_id=1) p
on p.path like tab.path + '%' or tab.path like p.path + '%'