2017-09-22 4 views
0

난이 조인 table (id, employee_id, device_id, logged_time) [간략화] 생체 인식 장치에서 종업원의 출석을 기록. 각 직원의 첫 번째 및 마지막 시간을 날짜별로 보여주는 보고서를 생성합니다.선택 항목 (들)

현재 각 직원의 첫 번째 및 마지막 시간을 날짜별로 가져올 수 있지만 각 직원의 첫 번째 및 마지막으로 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 

의 날짜별로 시작 및 종료 시간이 표시됩니다

0 : 날짜 범위

시도
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`; 

제공

case을 사용하는 각 날짜의 최대 및 최소 logged_time과 유사하게 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

+0

날짜 별 동적 열에 대한 이유는 무엇입니까? 매우 "비협조적인"것으로 보인다 ... –

+0

@RomanSusi, 기본적으로 쿼리의 결과는 "생성 된 보고서"(일부 변경 사항이 있음)이며이 기능은 비슷하지만 기능이 다른 여러 곳에서도 사용됩니다. 전체 월 또는 월에 대한 모든 직원의 일일 출석 데이터를 가져 와서 응용 프로그램 측면에서이 차트를 처리 (교대조, 일정 등에 관한 추가 계산 포함)하면 잠재적으로 복잡해지고 데이터가있을 때 시간과 메모리 문제가 발생할 수 있습니다. 거대한. 데이터베이스에서이 작업을 수행하면 확장이 잘 된 것 같습니다. 더 나은 방법에 대한 제안을 보내 주시면 감사하겠습니다. – Shuvo

답변

0

결과와 GROUP_CONCAT를 사용하여 안팎의 장치 ID를 선택하는 쿼리에 SUBSTRING_INDEX

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, 

또는 경우 장치 ID가 동일합니다에 대한 빠른 해킹 각 in과 out에 대해 간단히 GROUP_CONCAT으로 쓸 수 있습니다.

GROUP_CONCAT(DISTINCT case when DATE(`l`.`logged_time`) = '2017-09-18' THEN `l`.`device_id` END) 
방지하기 위해 10

DEMO

+0

은'logged_time'에 의한 주문이 아니고'device_id'에 의한 주문이 아니겠습니까? 그리고'device_id'도 입력과 종료가 다릅니다. 규모가 얼마나 좋을지 관심이 있습니까? 잠재적으로 100 개의 열과 수천 개의 행이있을 수 있습니다. – Shuvo

+0

아니요 주문할 때 device_id가 아니며 이미 이것을 조건으로 사용하고 있기 때문에 logged_time이 될 수 없습니다. 제공되는 데이터 세트에 따르면 동일한 ID가 있기 때문에 두 솔루션을 게시했습니다. 이미 작성한 방식을 확장하기 위해 더 큰 데이터에 대해 스케일을 조정할 수 없기 때문에이를 빠른 해킹이라고합니다. –

+0

샘플 데이터 세트 일종의 요약이며 실제 데이터를 완전히 반영하지 못할 수 있습니다. 그렇다면'device_id'에 의한 엔트리와 엔트리 디바이스의 순서는 어떻게됩니까? ''합치기 '는'substring'과'group_concat' 대신에 널이 아닌 첫 번째'device_id'를 얻기 위해 사용될 수 있습니다. 또한 이러한 쿼리를 개선하는 방법에 대한 제안 사항이 있습니까? – Shuvo

0

내가 대신 "상관 하위 쿼리를"시도 제안 조인

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()를 사용했다 이들이 하나 이상의 값을 반환 할 가능성을 피하기 위해서입니다. 원하는 경우 한도를 대신 사용할 수 있습니다.

참고 : 일반적으로 상관 하위 쿼리는 성능 문제를 일으킬 수 있으므로 권장하지 않지만 필요한 데이터를 제공합니다.

아, 열 이름으로 date을 사용하지 마십시오. 좋은 습관이 아닙니다.

+0

외부 쿼리 결과 집합이 매우 큰 경우 상관 관계가있는 하위 쿼리가 성능 문제가되지 않습니까? 결과 집합이 클수록 상관 관계가있는 하위 쿼리는 사용하지 않았습니다. 실제 테이블에는 2 백만 개 이상의 레코드가 있고 성장할 수 있습니다. 쿼리는 한 번에 500 개를 가져 와서 페이지가 매겨집니다. – Shuvo

+0

예 (이미 언급했듯이). 조인을 배제 했으므로 사용 가능한 옵션이 줄어 듭니다. 지금까지 내가 본 것처럼 당신은이 상관 된 쿼리에 붙어 있습니다. –