Группировка элементов с равномерным распределением в SQL - PullRequest
0 голосов
/ 16 марта 2012

Рассмотрим таблицу учеников с 104 строками в ней. Мне нужно создать группы с минимум 10 студентами в каждой группе. В случае с 104 учениками у меня было бы 10 групп по 10 учеников и 1 группа по 4 ученика, если я проведу по каждому ученику и создам группу. Существует правило, что в группе с оставшимися студентами не может быть менее 5 студентов (в этом случае последняя группа состоит из 4 студентов). Два возможных подхода я пытаюсь сделать:

  1. Сверните последнюю группу, в которой менее 5 учеников, и назначьте каждую из них в любую группу, или
  2. Равномерно распределите последнюю группу по любым группам.

Как мне достичь чего-либо из этого? Большое спасибо.

Eric

Ответы [ 2 ]

2 голосов
/ 16 марта 2012

Вы можете использовать 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 .

0 голосов
/ 16 марта 2012

Вот вариант 2. Первая часть готовит счетчики. Поскольку у меня нет данных о студентах, я решил создать временную таблицу из строк @maxStudents только с одним идентификатором столбца.

First cte (Students) генерирует список студентов строк maxStudents. Секунда (-ы) извлекает студентов, присваивая им номер строки (очевидно, здесь нет необходимости, но это важно, когда вы подключаете запрос, который извлекает студентов). Также возвращает количество студентов.

Третья часть размещает студентов в группы. Учащиеся, принадлежащие к последней группе, будут перемещены в другую группу, если они принадлежат к последней группе, имеющей менее @minGroupSize членов. Первой версии можно добиться, заменив затем часть в операторе 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...