Mysql 如何在SQL中(递归地)确定等价分组?
我有一个由SKU标识的产品列表。为了简化它,我只把它们命名为A,B,C,D,。。。在这里默认情况下,这些SKU中的每一个都分配了一个已经存在的Mysql 如何在SQL中(递归地)确定等价分组?,mysql,sql,Mysql,Sql,我有一个由SKU标识的产品列表。为了简化它,我只把它们命名为A,B,C,D,。。。在这里默认情况下,这些SKU中的每一个都分配了一个已经存在的GroupID,为简单起见,我只将它们编号为1、2、3、,。。。在这里 相同的GroupID意味着“这些SKU是等效的,因此可以使用/购买其中任何一个,因为这没有区别” 问题是,一些SKU不止一次地出现,因为它们来自不同的购买来源,但由于它们来自不同的来源,它们有不同的分组 因此,目标是合并分组,并确保它们具有相同的分组 如果我的插图不够漂亮,我已经道歉了
GroupID
,为简单起见,我只将它们编号为1、2、3、,。。。在这里
相同的GroupID
意味着“这些SKU是等效的,因此可以使用/购买其中任何一个,因为这没有区别”
问题是,一些SKU不止一次地出现,因为它们来自不同的购买来源,但由于它们来自不同的来源,它们有不同的分组
因此,目标是合并分组,并确保它们具有相同的分组
如果我的插图不够漂亮,我已经道歉了,但我正在努力。下面是一个关于原始数据外观的小数据表示例(第一行是列名):
结果应该是:
Source SKU GroupID
Seller1 A 1
Seller1 B 1
Seller1 C 1
Seller2 B 1
Seller2 D 1
Seller2 E 1
Seller3 A 1
Seller3 B 1
Seller4 F 4
Seller4 G 4
Seller4 H 4
基本上,如果GroupID X中的任何SKU是GroupID Y的子集,那么GroupID Y=GroupID X。但这应该应用于所有GroupID,因此它似乎是递归的
我希望我能展示我已经试过的代码,我已经试了几天了,但实际上我只产生了垃圾
在C#中,我知道如何处理这一点,但我似乎无法对SQL进行思考,因为我没有那么丰富的经验,不幸的是,我需要SQL中的这一点
我会感谢你们的任何帮助,即使这只是你们建议我尝试的一个提示或方向。非常感谢 首先是根据计数获取所有具有子集的卖家。然后使用GROUPBY进行过滤
select table1.Source, SKU, case when table1.Source = t6.Source and t6.cnt > 1 then 1 else 2 end as GroupID
from table1
left join
(select t5.Source, count(t5.cnt) as cnt from (
select distinct t4.Source, t4.cnt from (
select t3.Source, count(t3.SKU) as cnt from (
select t1.Source, t1.SKU from table1 t1
left join table1 t2 on t2.SKU = t1.SKU ) t3
group by t3.Source, t3.SKU
order by t3.Source) t4) as t5
group by t5.Source) t6 on t6.Source = table1.Source
首先是让所有这些卖家根据数量进行子集。然后使用GROUPBY进行过滤
select table1.Source, SKU, case when table1.Source = t6.Source and t6.cnt > 1 then 1 else 2 end as GroupID
from table1
left join
(select t5.Source, count(t5.cnt) as cnt from (
select distinct t4.Source, t4.cnt from (
select t3.Source, count(t3.SKU) as cnt from (
select t1.Source, t1.SKU from table1 t1
left join table1 t2 on t2.SKU = t1.SKU ) t3
group by t3.Source, t3.SKU
order by t3.Source) t4) as t5
group by t5.Source) t6 on t6.Source = table1.Source
您需要组之间的对应关系,可以使用递归CTE进行计算:
with recursive tt as (
select distinct t1.groupid as groupid1, t2.groupid as groupid2
from t t1 join
t t2
on t1.sku = t2.sku
),
cte as (
select tt.groupid1, tt.groupid2, concat_ws(',', tt.groupid1, tt.groupid2) as visited
from tt
union all
select cte.groupid1, tt.groupid2, concat_ws(',', visited, tt.groupid2)
from cte join
tt
on cte.groupid2 = tt.groupid1
where find_in_set(tt.groupid2, cte.visited) = 0
)
select groupid1, min(groupid2) as overall_group
from cte
group by groupid1;
然后,您可以将其连接回原始表,以获得“总体组”:
他是一把小提琴
注意:您的示例数据相当“完整”,因此对于该特定数据不需要递归CTE。但是,我猜实际组的重叠较少,在这种情况下,递归是必要的。您需要组之间的对应关系,可以使用递归CTE计算:
with recursive tt as (
select distinct t1.groupid as groupid1, t2.groupid as groupid2
from t t1 join
t t2
on t1.sku = t2.sku
),
cte as (
select tt.groupid1, tt.groupid2, concat_ws(',', tt.groupid1, tt.groupid2) as visited
from tt
union all
select cte.groupid1, tt.groupid2, concat_ws(',', visited, tt.groupid2)
from cte join
tt
on cte.groupid2 = tt.groupid1
where find_in_set(tt.groupid2, cte.visited) = 0
)
select groupid1, min(groupid2) as overall_group
from cte
group by groupid1;
然后,您可以将其连接回原始表,以获得“总体组”:
他是一把小提琴
注意:您的示例数据相当“完整”,因此对于该特定数据不需要递归CTE。但是,我猜您的真实组重叠较少,在这种情况下,递归是必要的。哪个版本的MySQL?@Nick我使用的是最新的8.0社区版版本Seller2没有任何子集,为什么它会返回groupID 1?@EdBangga B是groupID 1的一个子集我花了一些时间浏览了@GordonLinoff的代码并理解了它,但我感谢大家在这里的投入。非常感谢。哪个版本的MySQL?@Nick我使用的是最新的8.0社区版版本Seller2没有任何子集,为什么它返回groupID 1?@EdBangga B是groupID 1的一个子集我花了一些时间浏览了@GordonLinoff的代码并理解了它,但我感谢大家在这里的输入。非常感谢。你说得对,真正的组重叠较少,因此递归是必要的。非常感谢,你的回答非常有帮助,也很有见地:)你是对的,真正的组重叠较少,因此递归是必要的。非常感谢,你的回答很有帮助,也很有见地:)