在SQL中对具有均匀分布的项目进行分组

时间:2012-03-16 08:54:48

标签: sql-server-2008 tsql data-structures

考虑一个包含104行的学生表。我需要创建每组至少10名学生的小组。在有104名学生的情况下,如果我对每个学生进行迭代并创建分组,我最终会得到10组10名学生和1组4名学生。有一个规则是,剩下学生的小组中不能少于5名学生(在这种情况下,最后一组由4名学生组成)。我正试图做的两种可能的方法:

  1. 汇总少于5名学生的最后一个小组,并将每个小组分配给任何小组,或
  2. 将最后一组均匀分布到任何群组。
  3. 我如何实现这些目标?非常感谢。

    埃里克

2 个答案:

答案 0 :(得分:2)

您可以使用ntile

  

将有序分区中的行分配到指定的数字   团体这些组从一开始编号。对于每一行,   NTILE返回该行所属的组的编号。

一些示例代码:

declare @NumberOfStudents int
declare @StudentsPerGroup int

set @StudentsPerGroup = 10
set @NumberOfStudents = 104

select StudentID,
       ntile(@NumberOfStudents / @StudentsPerGroup) over(order by StudentID) as GroupID
from Students

SE-Data上试用。

答案 1 :(得分:0)

这是变体2.第一部分准备计数器。由于我没有关于学生的任何数据,我决定创建一个只有一个列ID的@maxStudents行的临时表。

第一个cte(学生)生成一个maxStudents行的学生列表。秒提取学生为他们分配行号(显然这里没有必要,但在插入检索学生的查询时必不可少)。它还会返回学生人数。

第三部分将学生分成小组。属于最后一组的学生将被重新安置到另一组,如果他们属于具有少于@minGroupSize成员的最后一组。第一版可以通过将例如1的case语句替换为第1组来实现。

declare @group_size int
set @group_size = 10
declare @maxStudents int
set @maxStudents = 104
declare @minGroupSize int
set @minGroupSize = 5

;with students as (
     select 1 id
     union all
     select 2 * id + b
          from students cross join (select 0 b union all select 1) b
          where 2 * id + b <= @maxStudents
),
s as (
    select students.id, row_number() over(order by students.id) - 1 rowNumber, count (*) over () TotalStudents
      from students
)
select s.id StudentID, 
       case when TotalStudents % @group_size < @minGroupSize
                 and rowNumber >= (TotalStudents / @group_size * @group_size)
            then rowNumber - (TotalStudents / @group_size * @group_size)
            else rowNumber / @group_size
            end + 1 Group_number
  from s
  order by 2, 1