php - 我们如何随机分配员工的职责
问题描述
我正试图允许三班倒值班
有以下约束:
1st shift will have 5 employee
>2nd shift will have 3 employee
3rd shift will have 2 employee
如果一个人在任何班次中被分配了职责,他将不会被允许再工作两班。前任。如果 X 先生在 8 月 3 日的第 2 班值班,那么他将不会在 8 月 3 日的第 3 班班次和 8 月 4 日的第 1 班班次值班
我已经使用rand()
函数来随机选择员工。我正面临约束 4 的问题。即,我如何确保在第一班被分配职责的员工不会在第二或第三班被分配
我的 MySQL 查询是:
SELECT * FROM `employee` ORDER BY rand()
解决方案
我认为这是一个很难用 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 可以落入的范围。范围大于雇员列表,因此您必须使用雇员表的大小作为范围的模数。
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 |
+----------+-------------+-----------+
我想我可以将最后一步作为练习留给读者。
推荐阅读
- html - 如何在没有 JS/PHP 的情况下将表单数据从一个 html 文件传递到另一个文件?
- powershell - 电源外壳。循环遍历证书存储并根据指纹删除证书
- c# - 为什么我发布后我的服务器设置没有被读取?
- python - python 可以在 MS Access 中使用而无需链接到数据库吗
- amazon-web-services - Cassandra 在启动后几分钟内因内存不足而崩溃
- html - 使用css旋转图像而不绕圈移动
- c# - 将十六进制参数传递给 RDLC
- android - openid app auth 自定义社交登录给出异常 ANDROID
- python - 如何在python中计算每15行的百分位数
- arrays - 局部和全局数组和分段错误