mardi 19 octobre 2021

Create equal sized, random buckets, with no repetition to the row

Having some difficulty in a scheduling task.

Background: I have 100 members, 10 different sessions, and 10 different activities. Rules:

  1. Each member must do each activity only once.
  2. Each activity must have the same number of members in each session.
  3. The members must be with (at least mostly) different people in each session.

The expected outcome would be something like this:

Person ID Session ID Activity ID
1 S1 A
2 S1 B
3 S1 C
1 S2 B
2 S2 C
3 S2 A

In the above example, each activity in each session has only 1 participant, I have to lock that activity in that session out at 10 members.

I have tried a few different solutions in excel / SQL, but not able to meet all 3 rules. The hardest being keeping each activity/session slot to 10 people.

The closest solution I've had is the following.. its not pretty though:

SET STATISTICS TIME, io OFF

-- Create list of applicants
IF OBJECT_ID('process.Numbers') IS NOT NULL DROP TABLE process.Numbers

CREATE TABLE Numbers (ApplicantID INT, SessionID INT, GroupID INT)

DECLARE @i       INT,
        @Session INT,
        @Group   INT;

SELECT @i = 1;

SET NOCOUNT ON

WHILE @i <= 100
    BEGIN
        INSERT INTO Numbers (ApplicantID, SessionID) VALUES (@i, 1);

        SELECT @i = @i + 1;
    END;

-- Duplicate ApplicantID list for each different session
SELECT @Session = 1

WHILE @Session <= 10
    BEGIN
        IF @Session > 1
            BEGIN
                INSERT INTO
                    Numbers (ApplicantID, SessionID)
                    SELECT ApplicantID, @Session FROM Numbers WHERE SessionID = 1
            END

        -- SELECT RANDOM TOP 10 AND SET AS GROUP ID

        SELECT @Group = 1

        WHILE @Group <= 10
            BEGIN
                WITH dups_check AS (   SELECT ApplicantID,
                                              GroupID,
                                              COUNT(*) AS vol
                                       FROM Numbers
                                       GROUP BY ApplicantID,
                                                GroupID),
                     cte AS (   SELECT TOP 10 *
                                FROM Numbers
                                WHERE numbers.GroupID IS NULL
                                      AND SessionID = @Session
                                      AND NOT EXISTS (SELECT 1
                                                      FROM dups_check
                                                      WHERE Numbers.ApplicantID = dups_check.ApplicantID
                                                            AND dups_check.GroupID = @Group)
                                ORDER BY newid())
                UPDATE cte SET GroupID = @Group

                SELECT @Group = @Group + 1
            END

        SELECT @Session = @Session + 1
    END

SELECT * FROM Numbers

SET NOCOUNT OFF

This code starts to fall over regularly in the higher session numbers when it tries to set an activity that the individual has already done.

Thanks!




Aucun commentaire:

Enregistrer un commentaire