鉴于人与人之间的关系,找到家庭团体

时间:2014-12-14 10:50:18

标签: sql sql-server sql-server-2012 grouping

我需要从规范化的人与人之间的关系数据中返回家庭群组

存储人与人之间关系的数据采用以下结构(我无法更改),其中人与人之间的每个关系都以一对行表示,并标识每一方并使用FK到表中的相关行。

create table myRelationships (
    id int
   ,PersonID int
   ,RelatedRowID int -- this is a FK to id for the related pair row
   ,RelationshipTypeID int -- not important for the purposes of this question
)

我可以在一行中明智地返回每个关系:

select
    r1.PersonID as Person1ID
   ,r2.PersonID as Person2ID
   ,r1.RelationshipTypeID as P1toP2RelationshipType
from
    myRelationships as r1
    left join myRelationships as r2 on r1.RelatedRowID=r2.id
where
    r1.PersonID<r2.PersonID -- so we don't get the same relationship in mirror-image as a 'duplicate'

我现在需要按照'家庭'对这些数据进行分组,其中所有人都是直接或n度相关的相关人员(例如与某人有关的人... )被分组到同一个桶中。以下是一些示例数据和预期结果。请注意,在这种情况下,关系类型并不重要 - 假设所有关系类型都表达符合我的家庭分组标准的家庭关系。

insert into myRelationships
    values (1,1,2,1)
          ,(2,2,1,1)
          ,(3,1,4,1)
          ,(4,3,3,1)
          ,(5,4,6,1)
          ,(6,5,5,1)
          ,(7,1,8,1)
          ,(8,6,7,1)
          ,(9,7,10,1)
          ,(10,15,9,1)
          ,(11,8,12,1)
          ,(12,15,11,1)

期望的输出

FamilyGroup PersonID
1           1
1           2
1           3
1           6
2           4
2           5
3           7
3           8
3           15

2 个答案:

答案 0 :(得分:3)

如何使用CTE执行此操作的示例:s。出于性能原因,您可能希望将一些CTE分解为带有索引的临时表。

编辑,第一个解决方案无效。这是一个新的尝试,在树的上下都有递归。因此,我需要跟踪我在“&#39;列表”中列出的内容。 (在此代码中只调用x的列)。通过这种方式,您可以找到每个人的最小相关ID,然后您可以对该最小ID进行分组。不确定这对大型数据集是否足够高效。

with ordered_relations as (
    select r1.PersonID as id1, r2.PersonID as id2
    from myRelationships r1
        inner join myRelationships r2 on r2.id = r1.RelatedRowID
    where r1.PersonID < r2.PersonID
)
, rec as (
  select ',' + cast(r.id1 as varchar(max)) + ',' x, r.id1 as id, r.id1 as minid
  from ordered_relations r
  union all
  select x + cast(r.id2 as varchar) + ',', r.id2, t.minid
  from rec t
    inner join ordered_relations r on r.id1 = t.id
    and not t.x like '%,' + cast(r.id2 as varchar) + ',%'
  union all
  select x + cast(r.id1 as varchar) + ',', r.id1, case when r.id1 < t.minid then r.id1 else t.minid end
  from rec t
    inner join ordered_relations r on r.id2 = t.id
    and not t.x like '%,' + cast(r.id1 as varchar) + ',%'
)
select dense_rank() over (order by min(minid)) groupid, id
from rec
group by id;

答案 1 :(得分:0)

我多年来一直在使用这样的层次结构,而且我不知道如何构建一个能够获得所需输出的SQL语句。树形结构,也称为树形结构,对计算机来说非常有意义,但在现实生活中使用起来很痛苦。这就是Microsoft创建hierarchyid数据类型的原因。

http://msdn.microsoft.com/en-us/library/bb677213(v=sql.110).aspx

由于您已经说过无法更改现有数据表,如果要返回从SQL格式化的数据,则需要创建一个可以处理递归逻辑并返回数据表结构的存储过程,或创建公用表表达式(CTE)。

http://technet.microsoft.com/en-us/library/ms186243%28v=sql.105%29.aspx

您所称的“家庭组”,MSFT链接中有关呼叫级别的示例。