我有一张名为clock的表,它可以全天跟踪员工的工作时间。记录的类型为0,1,2或3为开始班次,开始休息,结束休息,结束班次 - 按该顺序。员工每天可以休息多次。如何使用列start_time,end_time和length返回所有中断。
表记录示例: Table Records
输出示例: Output Example
这是当前使用的SQL查询,我不得不删除第二个中断时间(记录ID 44和45)来运行它:
SELECT
@start := (SELECT time as start FROM clock WHERE employeeID = 1 AND time BETWEEN
(SELECT time FROM clock WHERE employeeID = 1 AND type=0 ORDER BY UNIX_TIMESTAMP(time) DESC LIMIT 1) AND CURRENT_TIMESTAMP AND type = 1) as start_time,
@end := (SELECT time as end FROM clock WHERE employeeID = 1 AND time BETWEEN
(SELECT time FROM clock WHERE employeeID = 1 AND type=0 ORDER BY UNIX_TIMESTAMP(time) DESC LIMIT 1) AND CURRENT_TIMESTAMP AND type = 2) as end_time,
TIMEDIFF(@end, @start) as length
抱歉,我没有自己谷歌的SQL词汇,我一直在论坛上告诉操作人员将子查询的结果限制为1,我需要他们所有的休息时间才能返回。
[编辑0:刚刚意识到我的第二张图片有一个误导性的专栏。最后一列应为长度]
[编辑1:很抱歉,我刚刚创建了我的帐户,但是无法发布链接。这是一个sql小提琴示例http://sqlfiddle.com/#!9/bc49e9/1/0]
答案 0 :(得分:0)
为了使用连续数据执行所需操作,您需要使用LAG
分析函数。事情是Mysql还不支持它。所以你必须模仿它的行为。
LAG
函数基本上允许您使用以前的行值(基于顺序和分组)。
要在MySql中执行此操作,您必须使用一些变量和子查询。以下是您需要的查询:
SELECT t.employeeID,
t.starttime,
t.endtime,
date_format(TIMEDIFF(t.endtime, t.starttime), '%H:%i:%s') as length
FROM (SELECT clk.employeeID,
clk.`type`,
@lag AS starttime,
(@lag := clk.`time`) AS endtime
FROM (SELECT c.*
FROM (SELECT @_type = NULL,
@lag := NULL) vars,
clock c
ORDER BY c.employeeID,
c.`time`
) clk
WHERE (CASE WHEN @_type IS NULL
OR @_type <> type
THEN @lag := NULL
ELSE NULL END) IS NULL
AND (@_type := type) IS NOT NULL
) AS t
WHERE t.`type` = 2
AND t.starttime IS NOT NULL;
在此处查看:http://sqlfiddle.com/#!9/239b23/18
解释我对外部查询所做的过滤器:
WHERE t.`type` = 2
AND t.starttime IS NOT NULL;
没有过滤器的此查询的行为是获取此案例endtime alias
中的值及其先前值。如果你没有放置这个过滤器,第一行会出现null, 2016-06-01 16:04:07
的开始和结束(如果只过滤类型1,2),因此我们取出了start为null的列。
t.type = 2
过滤器将取出不需要的值,因为它按员工和类型“分组”。如果没有这些过滤器,请查看它是如何工作的:http://sqlfiddle.com/#!9/239b23/21
请注意,在第二个链接上,由于外部过滤器AND type in (1,2)
t.type = 2