编辑:这更难解释我,但是,根据评论不断编辑。感谢大家的兴趣。
我有一张这样的表
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 :(得分:1)
我把你的桌子命名为t。如果这是你想要的,请尝试。
它的表现与之匹配且无与伦比。
它正在寻找具有相同行数(t1.cnt = t2.cnt
)并且所有行都匹配(having COUNT(*) = t1.cnt
)的parentids。
你可以尝试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
<强>输出强>
config parentid1
ConfigA 1
ConfigA 3
ConfigB 2
ConfigB 4
如果id 14是ChildTypeZ,那么parentid 2和4将不匹配。这将是输出:
config parentid1
ConfigA 1
ConfigA 3
ConfigC 2
ConfigD 4
答案 1 :(得分:0)
我碰巧有类似的任务。我正在使用的数据规模有点大,所以我必须找到一种有效的方法。基本上我找到了两种工作方法。
一个是纯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
另一个有点棘手,使用它时必须小心。但令人惊讶的是,它并没有那么糟糕。这个想法是将子连接成大字符串然后按这些字符串分组。您可以使用任何可用的串联方法(如果您有SQL Server 2017,则使用xml技巧或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