テーブルをグループに分割する際に興味深い問題があります。私は観光客のグループを持っています - それぞれが単一の言語を話し、および/または家族の一員です. テーブルをグループに分割する必要がありますが、家族や似た言語の話者を一緒に保ちたいと考えています。
観光客を 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 人の家族を含む、すべての言語 1 の話者によって形成されます。
グループ 2 は、2 人のファミリー メンバー (5、6) と 1 人のランダム メンバー (9) によって形成され、3 人のグループになります。
グループ 3 は 2 人の同じ言語話者によって形成されます (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
質問
複数の列に基づいて行をグループ化して、テーブルを分割するためのより良い方法はありますか?