关系除法:在列中查找每组唯一的“子”值

时间:2014-02-14 16:55:08

标签: sql-server tsql relational-division

经过大量搜索后,似乎大多数relational division个问题都是针对具有匹配成员的群体。也许我有关键字问题,但我想要一些不同的东西:给定一个父母/小组和一组儿童/成员,如何找到每个独特的成员组合,无论父母是谁?

使用以下示例源

CREATE TABLE #m (Parent char(1), ChildID int)

INSERT INTO #m
VALUES ('a',1), ('a', 2), ('a',4),
       ('b',1), ('b', 3), ('b',4),
       ('c',1), ('c', 4), ('c',2),
       ('d',1), ('d',4),
       ('e',3), ('e', 1),
       ('f',4),
       ('g',3), ('g', 4), ('g',1);

SELECT * FROM #m

我正在寻找像(1,2,4),(1,3,4),(1,4),(1,3),(4)这样的结果,表示为新的临时表(连接回#m,以便每个Parent可以指向其#34;哈希"而不是匹配Parent

这个东西有lots of syntax variations个; this kind对我来说最有意义,但还没有得到答案。我无法找到重复的道歉。

编辑:表示为SQL结果集的所需结果:

UParent ChildID
------- -----------
u1      1
u1      2
u1      4
u2      1
u2      3
u2      4
u3      1
u3      4
u4      1
u4      3
u5      4

3 个答案:

答案 0 :(得分:2)

这使用for xml来构建一个排序的子ID列表,该列表用作rank()函数的分区子句。

select M.Parent,
       M.ChildID
from (
     select M1.Parent,
            M1.ChildID,
            rank() over(partition by (
                                     select cast(ChildID as varchar(11))+','
                                     from #m as M2
                                     where M1.Parent = M2.Parent
                                     order by M2.ChildID
                                     for xml path('')
                                     )
                        order by M1.Parent) as rn
     from #m as M1
     ) as M
where M.rn = 1;

SQL Fiddle

答案 1 :(得分:1)

我知道,你想要"独特的"儿童的组合,无论秩序如何。

以下内容获取相同的父母:

select m1.Parent as Parent1, m2.Parent as Parent2
from (select m.*, count(*) over (partition by Parent) as NumKids
      from #m m
     ) m1 join
     (select m.*, count(*) over (partition by Parent) as NumKids
      from #m m
     ) m2
     on m1.ChildID = m2.ChildID
group by m1.Parent, m2.Parent
having count(*) = max(m1.NumKids) and max(m1.NumKids) = max(m2.NumKids);

我们现在可以使用此

获得您想要的内容
with parents as (
    select m1.Parent as Parent1, m2.Parent as Parent2
    from (select m.*, count(*) over (partition by Parent) as NumKids
          from #m m
         ) m1 join
         (select m.*, count(*) over (partition by Parent) as NumKids
          from #m m
         ) m2
         on m1.ChildID = m2.ChildID
    group by m1.Parent, m2.Parent
    having count(*) = max(m1.NumKids) and max(m1.NumKids) = max(m2.NumKids)
)
select distinct m.*
from (select min(Parent2) as theParent
      from parents
      group by Parent1
     ) p join
     #m m
     on p.theParent = m.Parent;

如果您想要新ID而不是旧ID,请使用:

select dense_rank() over (partition by m.Parent) as NewId, m.ChildID
<{1>}中的

答案 2 :(得分:0)

如果我的数据存储方式错误,请更正我,不管它的格式是否有所不同。

我从您给定的示例数据中尝试了此查询,并生成了您期望的结果集。看看这里

SELECT 'u' + CAST(DENSE_RANK() OVER (ORDER BY Parent) AS VARCHAR(10)) AS UParent
      ,ChildID
FROM #m

结果集

╔═════════╦═════════╗
║ UParent ║ ChildID ║
╠═════════╬═════════╣
║ u1      ║       1 ║
║ u1      ║       2 ║
║ u1      ║       4 ║
║ u2      ║       1 ║
║ u2      ║       3 ║
║ u2      ║       4 ║
║ u3      ║       1 ║
║ u3      ║       4 ║
║ u3      ║       2 ║
║ u4      ║       1 ║
║ u4      ║       4 ║
║ u5      ║       3 ║
║ u5      ║       1 ║
║ u6      ║       4 ║
║ u7      ║       3 ║
║ u7      ║       4 ║
║ u7      ║       1 ║
╚═════════╩═════════╝