我们如何才能将员工的职责随机化

时间:2018-08-11 08:20:14

标签: php mysql

我正试图允许三班制上班

有以下约束条件:

1st shift will have 5 employee 
>2nd shift will have 3 employee
3rd shift will have 2 employee 

如果某人在任何轮班中被分配值班,则将不允许他再轮班两次。例如如果X先生在8月3日的第二班中被分配值班,那么他既不会在8月3日的第三班中得到值班,又不会在8月4日的第一班中得到值班

我已经使用rand()函数来随机选择员工。我面临约束4的问题。即,如何确保在第一班工作中分配工作的员工不会在第二班或第三班工作中被分配

我的MySQL查询是:

SELECT * FROM `employee` ORDER BY rand()

2 个答案:

答案 0 :(得分:0)

我认为这是SQL中很难解决的问题,但是如果我要尝试使用它,我可能会从随机分配员工开始...

DROP TABLE IF EXISTS employees;

CREATE TABLE employees 
(employee_id SERIAL PRIMARY KEY);

INSERT INTO employees VALUES
(101),(102),(103),(104),(105),(106),(107),(108),(109),(110);

SELECT employee_id,@i:=@i+1 i FROM (SELECT employee_id FROM employees ORDER BY RAND()) x,(SELECT @i:=0) vars;
+-------------+------+
| employee_id | i    |
+-------------+------+
|         108 |    1 |
|         109 |    2 |
|         110 |    3 |
|         103 |    4 |
|         105 |    5 |
|         106 |    6 |
|         102 |    7 |
|         104 |    8 |
|         107 |    9 |
|         101 |   10 |
+-------------+------+

现在,只要我们拥有至少3天的员工(5 + 3 + 2 = 10),我们就可以循环浏览该列表,并知道每个员工将始终拥有至少连续两个休息日在每个工作日之间。

这是问题的另一个方面的想法...

DROP TABLE IF EXISTS shifts;

CREATE TABLE shifts 
(shift_id SERIAL PRIMARY KEY
,shift_size INT NOT NULL
);

INSERT INTO shifts VALUES
(1,5),(2,3),(3,2),(4,3),(5,2);

SELECT shift_id
     , ROUND(COALESCE(@j:=@prev+1,1),0) range_start
     , range_end, @prev:=range_end 
  FROM 
     ( SELECT x.*
            , SUM(y.shift_size) range_end 
         FROM shifts x 
         JOIN shifts y 
           ON y.shift_id <= x.shift_id 
        GROUP 
           BY x.shift_id
     ) b
     , ( SELECT @j:=1,@prev:=null) vars
 ORDER 
    BY shift_id;
+----------+-------------+-----------+------------------+
| shift_id | range_start | range_end | @prev:=range_end |
+----------+-------------+-----------+------------------+
|        1 |           1 |         5 |                5 |
|        2 |           6 |         8 |                8 |
|        3 |           9 |        10 |               10 |
|        4 |          11 |        13 |               13 |
|        5 |          14 |        15 |               15 |
+----------+-------------+-----------+------------------+

因此,现在您有了一个员工序列ID和一个可以放入这些ID的范围。该范围大于员工列表,因此您必须使用employees表的大小作为范围的模数。

 SELECT a.shift_id
      , MOD(a.range_start-1,(SELECT COUNT(*) FROM employees))+1 range_start
      , MOD(a.range_end-1,(SELECT COUNT(*) FROM employees))+1 range_end
   FROM
      ( SELECT shift_id
      , ROUND(COALESCE(@j:=@prev+1,1),0) range_start
      , range_end, @prev:=range_end
   FROM
      ( SELECT x.*
             , SUM(y.shift_size) range_end
          FROM shifts x
          JOIN shifts y
            ON y.shift_id <= x.shift_id
         GROUP
            BY x.shift_id
      ) b
      , ( SELECT @j:=1,@prev:=null) vars
  ORDER
     BY shift_id
     ) a
   ORDER BY shift_id;
+----------+-------------+-----------+
| shift_id | range_start | range_end |
+----------+-------------+-----------+
|        1 |           1 |         5 |
|        2 |           6 |         8 |
|        3 |           9 |        10 |
|        4 |           1 |         3 |
|        5 |           4 |         5 |
+----------+-------------+-----------+

我想我可以把最后一步留给读者练习。

答案 1 :(得分:-1)

由于您没有提供太多详细信息,因此很难弄清楚如何将信息存储在数据库中。我想以下查询适合您的情况:

SELECT * FROM employee e
WHERE e.employee_id NOT IN (
                            SELECT es.employee_id FROM emp_shifts es
                            WHERE shift IN (...)
                            )
ORDER BY RAND()

我假设您将轮班分配存储在emp_shifts表中。 ...是您要排除的最后2个班次。