2016-07-29 15 views
3

編集:これは私が、コメントに基づいてconstatly編集を説明するのは難しいです。興味を持っていただきありがとうございます。同じ子どもを持つグループ親

私はこの

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 

のようなテーブルを持っていると私は同じ子を持つグループの親にしたい - 同じタイプの子どもの数が同じ意味。

親の観点からは、可能な設定の有限集合(最大10)があります。

いずれかの親に同じ子セットがある場合(ChildTypeによる)、それらをまとめてグループ化したい(構成と呼ぶ)。

ChildTypeA-D = ConfigA 
ChildTypeA-C = ConfigB 
ChildTypeA, B, E, F = ConfigX 
etc. 

出力が必要なのは、コンフィグレーションによってグループ化された親です。

Config Group ParentID 
ConfigA   1 
ConfigA   3 
ConfigB   2 
ConfigB   4 

どこから始めるのかわかりません。

+0

私はまだあなたがどのようにasisgn configgroupを取得しないのですか – TheGameiswar

+0

設定の「有限集合」についてもっと詳しく説明してください。私たちは1-10構成か1k-100k構成について話していますか?代表的なデータを持つSQLフィドルを歓迎します。 –

答えて

1

私はあなたのテーブルに名前をつけました。これがあなたが探しているものであれば試してください。 これは、一致し、比類のない番組です。 同じ数の行(t1.cnt = t2.cnt)とすべての行が一致している子孫(having COUNT(*) = t1.cnt)を探しています。 ID 14がChildTypeZが、その後2をPARENTIDと4が一致しませんでした場合 あなたは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 

それを試すことができます。これは出力になります:

config parentid1 
ConfigA 1 
ConfigA 3 
ConfigC 2 
ConfigD 4 
0

私は同様のタスクを持っていることが起こりました。私が扱っているデータは少し大きかったので、私はこれに効果的なアプローチを見つけなければなりませんでした。基本的に私は2つの作業アプローチを見つけました。

1つは純粋なSQLです - ここではコアクエリです。基本的には、同じコレクションの子を持つ最小のParentIDをグループIDとして使用できます(row_numberで列挙することもできます)。小さなメモとして、私はここでcteを使っていますが、現実世界では、グループ化された親を一時テーブルに入れ、テーブルにインデックスを追加することをお勧めします。

;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 

もう1つは少しトリッキーなので、使用するときは注意が必要です。しかし驚くべきことに、それほど悪くはありません。アイデアは、子供を大きな文字列に連結し、次にこれらの文字列でグループ化することです。使用可能な連結方法(SQL Server 2017を使用している場合はxml trickまたはclr)を使用できます。重要な点は、すべての文字列がグループを正確に表すように順序付き連結を使用する必要があることです。私はこれのために特別なCLR関数(dbo.f_ConcatAsc)を作成しました。

;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 
関連する問題