我有一个有趣的问题是将表分成组。我有一群游客 - 每个人都说一种语言和/或是一个家庭的一部分。我需要将表格分成几组,但我想让家人和语言相似的人聚在一起。
假设我想将游客分成最多 3 人的组(如果组必须更大,这是可以接受的)。该解决方案不必太聪明以至于完全填满所有组,但我正在尽最大努力。
输入:
TouristID | LanguageID | FamilyID
---------------------------------
1 | 1 | 1
2 | 1 | 1
3 | 1 | 1
4 | 2 | 1
5 | 3 | 2
6 | 4 | 2
7 | 5 | 3
8 | 5 | 4
9 | 7 | 5
期望的结果:
TouristID | GroupID
-------------------
1 | 1
2 | 1
3 | 1
4 | 1
5 | 2
6 | 2
7 | 3
8 | 3
9 | 2
第 1 组由所有使用 1 语言的人组成,包括一位不能被排除在外的家庭成员。
第 2 组由两名家庭成员 (5, 6) 和一名随机成员 (9) 组成,组成 3 人组。
第 3 组由两个相同语言的人 (7, 8) 组成
我做了什么:
INSERT TouristGroup
SELECT
t.TouristID,
DENSE_RANK() OVER (ORDER BY GroupID) AS [GroupID]
FROM Tourists t
CROSS APPLY (
SELECT MIN(TouristID) AS [GroupID]
FROM Tourists t2
WHERE
( t2.LanguageID = t.LanguageID
OR t2.FamilyID = t.FamilyID )
) x;
INSERT Groups
SELECT GroupID, COUNT(*)
FROM TouristGroup
GROUP BY GroupID;
declare
@matchID int = 0,
@currentCount int,
@desiredCount int = 0,
@candidateGroupID int = null,
@chunk int = 1
while exists (
select null
from Groups g
left join Matches m
on m.GroupID = g.GroupID
where m.GroupID is null
)
begin
set @currentCount = null
set @candidateGroupID = null
select
@currentCount = isnull(SUM([Count]), 0)
from Matches m
join Groups g
on g.GroupID = m.GroupID
where m.MatchID = @matchID
if @CurrentCount is not null
begin
set @desiredCount = @chunk - @desiredCount
select top 1
@candidateGroupID = g.GroupID
from Groups g
left join Matches m
on m.GroupID = g.GroupID
where g.[Count] <= @desiredCount
and m.GroupID is null
order by [Count] DESC
if @candidateGroupID is not null
begin
insert Matches
select @matchID, @candidateGroupID
end
else begin
set @matchID = @matchID + 1
end
end
else begin
set @matchid = @matchID + 1
end
end
问题
是否有更好的方法来对表进行分区,但根据多列将行分组在一起?