Mysql Select 仅限具有指定连续空闲时间段数的员工
Mysql Select Only Staff with Specified Number of Consecutive Free Time Slots
每位员工在 AvailSlots 中已经有一个 table 个可用时段,如下所示:
Staff_ID Avail_Slots_Datetime
1 2015-1-1 09:00:00
1 2015-1-1 10:00:00
1 2015-1-1 11:00:00
2 2015-1-1 09:00:00
2 2015-1-1 10:00:00
2 2015-1-1 11:00:00
3 2015-1-1 09:00:00
3 2015-1-1 12:00:00
3 2015-1-1 15:00:00
我需要找出哪些员工在每个时段有 2 个(或 3 个、4 个等)连续可用时段。作为新手,如果查询是针对 2 个连续的时隙,我只知道下面的 INNER JOIN 代码。
SELECT a.start_time, a.person
FROM a_free a, a_free b
WHERE (b.start_time = addtime( a.start_time, '01:00:00' )) and (a.person = b.person)
但是,显然,这样做,我将不得不添加更多的 INNER JOIN 代码 - 对于每种情况 - 取决于查询是针对 3、4 还是 5 等连续可用时隙给出 date/hour。因此,我想学习一种更高效、更灵活的方法来做同样的事情。具体来说,我需要的查询代码(用自然语言)是这样的:
对于 AvailSlots 中的每个时间段,列出一名拥有 X 的员工(其中 X 可以
是我为每个查询指定的任何数字,从 1 到 24) 连续的日期时间
从该日期时间开始的插槽。如果不止一名员工可以见面
这个标准,抢七是他们的"rank",保存在
下面分开 table:
Ranking Table (lower number = higher rank)
Staff_ID Rank
1 3
2 1
3 2
如果答案是使用 "mysql variables"、"views" 等,请解释这些东西是如何工作的。再一次,作为一个总共 mysql 的新手,到目前为止,我所知道的只有 "select"、"join"、"where"、"group by"。我渴望了解更多,但目前无法理解更高级的 mysql 概念。非常感谢。
我使用的数据比您发布的多一些,找到了一个可能满足您需要的查询。它确实使用了您预测的变量 :) 但我希望它是不言自明的。让我们从 table:
开始
CREATE TABLE a_free
(`Staff_ID` int, `Avail_Slots_Datetime` datetime)
;
INSERT INTO a_free
(`Staff_ID`, `Avail_Slots_Datetime`)
VALUES
(1, '2015-01-01 09:00:00'),
(1, '2015-01-01 10:00:00'),
(1, '2015-01-01 11:00:00'),
(1, '2015-01-01 13:00:00'),
(2, '2015-01-01 09:00:00'),
(2, '2015-01-01 10:00:00'),
(2, '2015-01-01 11:00:00'),
(3, '2015-01-01 09:00:00'),
(3, '2015-01-01 12:00:00'),
(3, '2015-01-01 15:00:00'),
(3, '2015-01-01 16:00:00'),
(3, '2015-01-01 17:00:00'),
(3, '2015-01-01 18:00:00')
;
然后是查找连续插槽的查询。它列出每对的开始时间,并用唯一编号标记每组连续的时隙。 case 表达式是魔法发生的地方,见评论:
select
Staff_ID,
Avail_Slots_Datetime as slot_start,
case
when @slot_group is null then @slot_group:=0 -- initalize the variable
when @prev_end <> Avail_Slots_Datetime then @slot_group:=@slot_group+1 -- iterate if previous slot end does not match current one's start
else @slot_group -- otherwise just just keep the value
end as slot_group,
@prev_end:= Avail_Slots_Datetime + interval 1 hour as slot_end -- store the current slot end to compare with next row
from a_free
order by Staff_ID, Avail_Slots_Datetime asc;
识别出包含槽组的列表后,我们可以将上面的查询包装在另一个查询中,以获取每个槽组的长度。第一个查询的结果被视为任何其他 table:
select
Staff_ID,
slot_group,
min(slot_start) as group_start,
max(slot_end) as group_end,
count(*) as group_length
from (
select
Staff_ID,
Avail_Slots_Datetime as slot_start,
case
when @slot_group is null then @slot_group:=0
when @prev_end <> Avail_Slots_Datetime then @slot_group:=@slot_group+1
else @slot_group
end as slot_group,
@prev_end:= Avail_Slots_Datetime + interval 1 hour as slot_end
from a_free
order by Staff_ID, Avail_Slots_Datetime asc
) groups
group by Staff_ID, slot_group;
注意:如果再次使用同一个数据库连接执行查询,变量不会被重置,所以slot_groups编号会继续增长。这通常应该不是问题,但为了安全起见,您需要在之前或之后执行类似的操作:
select @prev_end:=null;
如果你愿意,可以玩fiddle:http://sqlfiddle.com/#!2/0446c8/15
每位员工在 AvailSlots 中已经有一个 table 个可用时段,如下所示:
Staff_ID Avail_Slots_Datetime
1 2015-1-1 09:00:00
1 2015-1-1 10:00:00
1 2015-1-1 11:00:00
2 2015-1-1 09:00:00
2 2015-1-1 10:00:00
2 2015-1-1 11:00:00
3 2015-1-1 09:00:00
3 2015-1-1 12:00:00
3 2015-1-1 15:00:00
我需要找出哪些员工在每个时段有 2 个(或 3 个、4 个等)连续可用时段。作为新手,如果查询是针对 2 个连续的时隙,我只知道下面的 INNER JOIN 代码。
SELECT a.start_time, a.person
FROM a_free a, a_free b
WHERE (b.start_time = addtime( a.start_time, '01:00:00' )) and (a.person = b.person)
但是,显然,这样做,我将不得不添加更多的 INNER JOIN 代码 - 对于每种情况 - 取决于查询是针对 3、4 还是 5 等连续可用时隙给出 date/hour。因此,我想学习一种更高效、更灵活的方法来做同样的事情。具体来说,我需要的查询代码(用自然语言)是这样的:
对于 AvailSlots 中的每个时间段,列出一名拥有 X 的员工(其中 X 可以 是我为每个查询指定的任何数字,从 1 到 24) 连续的日期时间 从该日期时间开始的插槽。如果不止一名员工可以见面 这个标准,抢七是他们的"rank",保存在 下面分开 table:
Ranking Table (lower number = higher rank) Staff_ID Rank 1 3 2 1 3 2
如果答案是使用 "mysql variables"、"views" 等,请解释这些东西是如何工作的。再一次,作为一个总共 mysql 的新手,到目前为止,我所知道的只有 "select"、"join"、"where"、"group by"。我渴望了解更多,但目前无法理解更高级的 mysql 概念。非常感谢。
我使用的数据比您发布的多一些,找到了一个可能满足您需要的查询。它确实使用了您预测的变量 :) 但我希望它是不言自明的。让我们从 table:
开始CREATE TABLE a_free
(`Staff_ID` int, `Avail_Slots_Datetime` datetime)
;
INSERT INTO a_free
(`Staff_ID`, `Avail_Slots_Datetime`)
VALUES
(1, '2015-01-01 09:00:00'),
(1, '2015-01-01 10:00:00'),
(1, '2015-01-01 11:00:00'),
(1, '2015-01-01 13:00:00'),
(2, '2015-01-01 09:00:00'),
(2, '2015-01-01 10:00:00'),
(2, '2015-01-01 11:00:00'),
(3, '2015-01-01 09:00:00'),
(3, '2015-01-01 12:00:00'),
(3, '2015-01-01 15:00:00'),
(3, '2015-01-01 16:00:00'),
(3, '2015-01-01 17:00:00'),
(3, '2015-01-01 18:00:00')
;
然后是查找连续插槽的查询。它列出每对的开始时间,并用唯一编号标记每组连续的时隙。 case 表达式是魔法发生的地方,见评论:
select
Staff_ID,
Avail_Slots_Datetime as slot_start,
case
when @slot_group is null then @slot_group:=0 -- initalize the variable
when @prev_end <> Avail_Slots_Datetime then @slot_group:=@slot_group+1 -- iterate if previous slot end does not match current one's start
else @slot_group -- otherwise just just keep the value
end as slot_group,
@prev_end:= Avail_Slots_Datetime + interval 1 hour as slot_end -- store the current slot end to compare with next row
from a_free
order by Staff_ID, Avail_Slots_Datetime asc;
识别出包含槽组的列表后,我们可以将上面的查询包装在另一个查询中,以获取每个槽组的长度。第一个查询的结果被视为任何其他 table:
select
Staff_ID,
slot_group,
min(slot_start) as group_start,
max(slot_end) as group_end,
count(*) as group_length
from (
select
Staff_ID,
Avail_Slots_Datetime as slot_start,
case
when @slot_group is null then @slot_group:=0
when @prev_end <> Avail_Slots_Datetime then @slot_group:=@slot_group+1
else @slot_group
end as slot_group,
@prev_end:= Avail_Slots_Datetime + interval 1 hour as slot_end
from a_free
order by Staff_ID, Avail_Slots_Datetime asc
) groups
group by Staff_ID, slot_group;
注意:如果再次使用同一个数据库连接执行查询,变量不会被重置,所以slot_groups编号会继续增长。这通常应该不是问题,但为了安全起见,您需要在之前或之后执行类似的操作:
select @prev_end:=null;
如果你愿意,可以玩fiddle:http://sqlfiddle.com/#!2/0446c8/15