2016-07-29 36 views
3

EDIT: Das ist viel schwieriger zu erklären, dass ich zwar, basierend auf Kommentaren ständig bearbeiten. Vielen Dank für Ihr Interesse.Gruppeneltern mit gleichen Kindern

Ich habe eine Tabelle wie diese

ID Type     ParentID 
1 ChildTypeA    1 
2 ChildTypeB    1 
3 ChildTypeC    1 
4 ChildTypeD    1 

5 ChildTypeA    2 
6 ChildTypeB    2 
7 ChildTypeC    2 

8 ChildTypeA    3 
9 ChildTypeB    3 
10 ChildTypeC    3 
11 ChildTypeD    3 

12 ChildTypeA    4 
13 ChildTypeB    4 
14 ChildTypeC    4 

und ich möchte zu einer Gruppe Eltern, die gleichen Kinder haben - gleiche Anzahl von Kindern gleichen Typs bedeutet.

Aus der übergeordneten Sicht gibt es eine begrenzte Anzahl möglicher Konfigurationen (max. 10).

Wenn ein Elternteil den gleichen Satz von Kindern (von ChildType) hat, möchte ich sie zusammen gruppieren (in dem, was ich eine Konfiguration nenne).

Die Ausgabe, die ich brauche, ist Eltern nach Konfigurationen gruppiert.

Config Group ParentID 
ConfigA   1 
ConfigA   3 
ConfigB   2 
ConfigB   4 

Ich habe keine Ahnung, wo ich anfangen soll.

+0

Ich bekomme immer noch nicht, wie Sie asisgn configgroup – TheGameiswar

+0

Könnten Sie ein wenig mehr auf Ihrem "endlichen Satz" von Konfigurationen erweitern? Sprechen wir von 1-10 Konfigurationen oder 1k-100k Konfigurationen? Eine SQL-Geige mit repräsentativen Daten ist willkommen. –

Antwort

1

Ich nannte Ihre Tabelle t. Bitte versuchen Sie es, wenn Sie das suchen. Es ist Show abgestimmt und unübertroffen. Es sucht nach Parentiden mit der gleichen Anzahl von Zeilen (t1.cnt = t2.cnt) und dass alle Zeilen übereinstimmen(). Sie können versuchen, es here

;with t1 as (select parentid, type, id, count(*) over (partition by parentid order by parentid) cnt from t), 
t3 as 
    (
     select t1.parentid parentid1, t2.parentid parentid2, count(*) cn, t1.cnt cnt1, t2.cnt cnt2, ROW_NUMBER() over (order by t1.parentid) rn 
      from t1 join t1 as t2 on t1.type = t2.type and t1.parentid <> t2.parentid and t1.cnt = t2.cnt 
     group by t1.parentid, t2.parentid, t1.cnt, t2.cnt 
     having COUNT(*) = t1.cnt 
    ), 
notFound as (
      select t1.parentid, ROW_NUMBER() over(order by t1.parentid) rn 
      from t1 
      where not exists (select 1 from t3 where t1.parentid = t3.parentid1) 
      group by t1.parentid 
     ) 
select 'Config'+char((select min(rn)+64 from t3 as t4 where t3.parentid1 in (t4.parentid1 , t4.parentid2))) config, t3.parentid1 
    from t3 
union all 
    select 'Config'+char((select max(rn)+64+notFound.rn from t3)) config, notFound.parentid 
    from notFound 

OUTPUT

config parentid1 
ConfigA 1 
ConfigA 3 
ConfigB 2 
ConfigB 4 

Wenn id 14 war ChildTypeZ ParentID dann 2 und 4 nicht entsprechen. Dies wäre die Ausgabe:

config parentid1 
ConfigA 1 
ConfigA 3 
ConfigC 2 
ConfigD 4 
0

Ich habe zufällig ähnliche Aufgabe haben. Die Daten, mit denen ich arbeite, sind etwas größer, daher musste ich einen effektiven Ansatz finden. Grundsätzlich habe ich 2 Arbeitsansätze gefunden.

Eins ist reines SQL - hier ist eine Kernabfrage. Im Grunde gibt es Ihnen die kleinste ParentID mit derselben Sammlung von Kindern, die Sie dann als Gruppen-ID verwenden können (Sie können sie auch mit row_number aufzählen). Als kleine Anmerkung - ich benutze cte hier, aber in der realen Welt würde ich vorschlagen, gruppierte Eltern in temporäre Tabelle zu setzen und Indizes auf dem Tisch auch hinzuzufügen.

;with cte_parents as (
    -- You can also use different statistics to narrow the search 
    select 
     [ParentID], 
     count(*) as cnt, 
     min([Type]) as min_Type, 
     max([Type]) as max_Type 
    from Table1 
    group by 
     [ParentID] 
) 
select 
    h1.ParentID, 
    k.ParentID as GroupID 
from cte_parents as h1 
    outer apply (
     select top 1 
      h2.[ParentID] 
     from cte_parents as h2 
     where 
      h2.cnt = h1.cnt and 
      h2.min_Type = h1.min_Type and 
      h2.max_Type = h1.max_Type and 
      not exists (
       select * 
       from (select tt.[Type] from Table1 as tt where tt.[ParentID] = h2.[ParentID]) as tt1 
        full join (select tt.[Type] from Table1 as tt where tt.[ParentID] = h1.[ParentID]) as tt2 on 
         tt2.[Type] = tt1.[Type] 
       where 
        tt1.[Type] is null or tt2.[Type] is null 
      ) 
     order by 
      h2.[ParentID] 
    ) as k 

ParentID GroupID 
----------- -------------- 
1   1 
2   2 
3   1 
4   2 

Eine andere ist ein bisschen schwieriger und Sie müssen vorsichtig sein, wenn Sie es verwenden. Aber überraschenderweise funktioniert es nicht so schlecht. Die Idee besteht darin, Kinder zu einer großen Zeichenfolge zu verketten und dann nach diesen Zeichenfolgen zu gruppieren. Sie können jede verfügbare Verkettungsmethode verwenden (xml trick oder clr, wenn Sie SQL Server 2017 haben). Der wichtige Teil ist, dass Sie eine geordnete Verkettung verwenden müssen, so dass jede Zeichenkette Ihre Gruppe genau repräsentiert. Ich habe dafür eine spezielle CLR-Funktion (dbo.f_ConcatAsc) erstellt.

;with cte1 as (
    select 
     ParentID, 
     dbo.f_ConcatAsc([Type], ',') as group_data 
    from Table1 
    group by 
     ParentID 
), cte2 as (
    select 
     dbo.f_ConcatAsc(ParentID, ',') as parent_data, 
     group_data, 
     row_number() over(order by group_data) as rn 
    from cte1 
    group by 
     group_data 
) 
select 
    cast(p.value as int) as ParentID, 
    c.rn as GroupID, 
    c.group_data 
from cte2 as c 
    cross apply string_split(c.parent_data, ',') as p 

ParentID GroupID    group_data 
----------- -------------------- -------------------------------------------------- 
2   1     ChildTypeA,ChildTypeB,ChildTypeC 
4   1     ChildTypeA,ChildTypeB,ChildTypeC 
1   2     ChildTypeA,ChildTypeB,ChildTypeC,ChildTypeD 
3   2     ChildTypeA,ChildTypeB,ChildTypeC,ChildTypeD