选择与没有连接的另一列的最大/最小相对应的列

时间:2017-09-22 18:39:25

标签: mysql sql join group-by case

我有tableidemployee_iddevice_idlogged_time [简化] < / strong>记录来自生物识别设备的员工的出勤情况。 我生成报告,显示每个员工按日期的第一个进出时间。

目前,我可以按日期获取每个员工的第一个进入和结束时间,但我还需要获取每个员工的第一个进入和结束device_id。条目不按记录时间的顺序排列。

我不希望(也可能不会)使用连接,因为在其中一个报告中,列是动态生成的,并且可能导致数千个连接。此外,这些是子查询,并与其他查询连接以获取更多详细信息。

表和查询的示例设置位于http://sqlfiddle.com/#!9/3bc755/4

第一个显示的是按每个员工的日期列出进入和退出时间

select
    attendance_logs.employee_id,
    DATE(attendance_logs.logged_time) as date,
    TIME(MIN(attendance_logs.logged_time)) as entry_time,
    TIME(MAX(attendance_logs.logged_time)) as exit_time
from attendance_logs
group by date, attendance_logs.employee_id

第二个是根据日期范围建立出勤图

select 
    `attendance_logs`.`employee_id`, 

    DATE(MIN(case when DATE(`attendance_logs`.`logged_time`) = '2017-09-18' THEN `attendance_logs`.`logged_time` END)) as date_2017_09_18, 
    MIN(case when DATE(`attendance_logs`.`logged_time`) = '2017-09-18' THEN `attendance_logs`.`logged_time` END) as entry_2017_09_18, 
    MAX(case when DATE(`attendance_logs`.`logged_time`) = '2017-09-18' THEN `attendance_logs`.`logged_time` END) as exit_2017_09_18, 

    DATE(MIN(case when DATE(`attendance_logs`.`logged_time`) = '2017-09-19' THEN `attendance_logs`.`logged_time` END)) as date_2017_09_19, 
    MIN(case when DATE(`attendance_logs`.`logged_time`) = '2017-09-19' THEN `attendance_logs`.`logged_time` END) as entry_2017_09_19,
    MAX(case when DATE(`attendance_logs`.`logged_time`) = '2017-09-19' THEN `attendance_logs`.`logged_time` END) as exit_2017_09_19

    /*
     * dynamically generated columns for dates in date range
     */
from `attendance_logs` 
where `attendance_logs`.`logged_time` >= '2017-09-18 00:00:00' and `attendance_logs`.`logged_time` <= '2017-09-19 23:59:59' 
group by `attendance_logs`.`employee_id`;

尝试:

与使用logged_time的每个日期的最大值和分钟case类似,尝试选择device_id logged_time最大/最小值。

```MIN(case 
    when 
    `attendance_logs.logged_time` = MIN(
        case when DATE(`attendance_logs`.`logged_time`) 
        = '2017-09-18' THEN `attendance_logs`.`logged_time` END
    ) 
then `attendance_logs`.`device_id` end) as entry_device_2017_09_18 ```

这导致invalid use of group by

2 个答案:

答案 0 :(得分:0)

使用GROUP_CONCAT

中的SUBSTRING_INDEX快速查找您的查询以选择进出的设备ID
SUBSTRING_INDEX(GROUP_CONCAT(case when DATE(`l`.`logged_time`) = '2017-09-18' THEN `l`.`device_id` END ORDER BY `l`.`device_id` desc),',',1) exit_device_2017_09_18,

或者,如果每个in和out的设备ID都相同,那么只需用GROUP_CONCAT编写

GROUP_CONCAT(DISTINCT case when DATE(`l`.`logged_time`) = '2017-09-18' THEN `l`.`device_id` END) 

DEMO

答案 1 :(得分:0)

为避免加入,我建议您尝试相关的子查询&#34;代替:

select
    employee_id
  , logdate
  , TIME(entry_time)                       entry_time
  , (select MIN(l.device_id)
     from attendance_logs l
     where l.employee_id = d.employee_id
     and l.logged_time = d.entry_time)     entry_device
  , TIME(exit_time)                        exit_time
  , (select MAX(l.device_id)
     from attendance_logs l
     where l.employee_id = d.employee_id
     and l.logged_time = d.exit_time)      exit_device
from (
      select
          attendance_logs.employee_id
        , DATE(attendance_logs.logged_time) as logdate
        , MIN(attendance_logs.logged_time) as entry_time
        , MAX(attendance_logs.logged_time) as exit_time
      from attendance_logs
      group by
          attendance_logs.employee_id
        , DATE(attendance_logs.logged_time)
      ) d
;

请参阅:http://sqlfiddle.com/#!9/06e0e2/3

注意:我在这些子查询上使用了MIN()和MAX(),以避免它们返回多个值的可能性。如果您愿意,可以使用限制1

另请注意:我通常不建议使用相关子查询,因为它们可能会导致性能问题,但它们确实提供了您需要的数据。

哦,请尽量避免使用date作为列名,这不是一个好习惯。