2017-06-27 3 views
1

Ich habe eine Tabelle wie unten, enthält eine Reihe von Groups, die (in sich selbst) Values einzigartig enthalten. Ich möchte herausfinden, welche Gruppen vollständige Untergruppen anderer Gruppen sind. Gruppen sollten natürlich nicht als Teilmengen von sich selbst gezählt werden.Finden Sie Gruppen in SQL, die Teilmengen anderer Gruppen sind

GroupTable:

ID | Group | Value 
================== 
00 | A | 1 
01 | A | 2 
02 | A | 3 
03 | B | 1 
04 | B | 3 
05 | C | 7 
06 | D | 2 

Was ich will (Jedes Element in den Smaller Gruppen in den Bigger Gruppen enthalten):

Smaller | Bigger 
================ 
    B  | A 
    D  | A 

Ich habe ein paar verschiedene Abfragen versucht, aber ich kann Wickeln Sie meinen Kopf herum, wie man benötigt jedes Element in der Bigger Gruppe, um in der Samller Gruppe zu sein.

Das Beste, was ich habe in der Lage zu tun, ist dies, die Gruppen, die jeden passenden Value in einer anderen Gruppe finden soll enthalten. Wie kann ich die beliebige zu einer alle drehen?

-- Groups where G1 ⊆ G2 
SELECT G1.Group, G2.Group 
FROM GroupTable G1 
JOIN GroupTable G2 ON G2.Group <> G1.Group 
WHERE G1.Value = G2.Value 
GROUP BY G1.Group, G2.Group; 

Antwort

1

Das SQL-Beispiel unten erste schließt sich der [Gruppe] 's auf andere mit dem gleichen [Wert] s.

Ähnlich wie die Antwort von Sergio Prats, wenn die gesamten eindeutigen Werte einer verbundenen [Gruppe] die gleichen sind wie die gesamten eindeutigen Werte, die [Gruppe] insgesamt hat, dann behalte diese als [Kleiner].

Der CTE mit den Summen wird zum Zweck der Wiederverwendung in den Joins verwendet.

Und die top 1 with ties wird nur verwendet, um den größten [Bigger]

declare @GroupTable table (ID int identity(1,1), [Group] char(1), Value int); 

insert into @GroupTable ([Group], Value) values 
('A',1),('A',2),('A',3),('B',1),('B',3),('C',7),('D',2),('E',3); 

;with CTE as 
(
    select [Group], count(distinct [Value]) as Total 
    from @GroupTable 
    group by [Group] 
) 
select top 1 with ties 
Q1.Group1 as [Smaller], 
Q1.Group2 as [Bigger] 
from 
(
    select 
    t1.[Group] as Group1, 
    t2.[Group] as Group2, 
    count(distinct t1.Value) as Total1 
    from @GroupTable t1 
    join @GroupTable t2 ON (t1.Value = t2.Value AND t1.[Group] != t2.[Group]) 
    group by t1.[Group], t2.[Group] 
) Q1 
join CTE c1 on (Q1.Group1 = c1.[Group] and Q1.Total1 = c1.Total) 
left join CTE c2 on (Q1.Group2 = c2.[Group]) 
order by c2.Total desc, Q1.Group2; 

Returns zu halten:

Smaller Bigger 
B  A 
D  A 
E  A 
1

Angenommen, Sie haben keine doppelten Werte (wie Ihre Frage angibt), dann sind Sie sehr nah dran. Sie müssen grundsätzlich eine left join und having Klausel:

select gt.group as smaller_group, gr2.group as bigger_group 
from grouptable gt left join 
    grouptable gt2 
    on gt2.value = gt.value and 
     gt2.group <> gt.group 
group by gt.group, gr2.group 
having count(*) = count(gt2.group); 

Die having Klausel sagt, dass die Anzahl der Werte für eine bestimmte Gruppe die Zahl in der zweiten Gruppe übereinstimmt.

1

keine Duplikate pro Gruppe und Wert Angenommen, Sie können versuchen, diese:

SELECT G1.[Group] as smaller, G2.[Group] AS bigger FROM 
(SELECT [Group], count(*) AS Num FROM GroupTable GROUP BY [Group]) G1 
INNER JOIN 
(SELECT A1.[Group], A2.[Group] as SmallGroup, count(*) AS Num2 
    FROM GroupTable A1 INNER JOIN GroupTable A2 ON 
    A1.[Value] = A2.[Value] 
    WHERE A1.[Group] <> A2.[Group] 
    GROUP BY A1.[Group], A2.[Group]) G2 
    ON G1.[Group] = G2.SmallGroup 
    WHERE Num2 = Num