子查询返回多个记录

时间:2016-06-01 22:12:00

标签: mysql database subquery

我有一张名为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]

SQLFiddle

1 个答案:

答案 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