2016-10-22 4 views
0

enter image description here선택 시간 -

mysql을 나는 사람들의 테이블에 저장된 데이터를이 지역으로 이동하지, 그들은 내부 이동 시간과 그들이 밖으로 나가 시간, 매 라운드마다 1 명이다.
이 지역에 사람이없는 경우 5 분마다 확인 쿼리를 작성할 수 있습니까? 예를 들어
위의 표 :

범위 10시 10분 0초 10시 15분 0초에 => 어떤 클라이언트 10시 10분 0초에서까지 범위 10시 15분 0초
10시 14분 58초에 10:20:00 => 클라이언트 10:15:00 ~ 10:20:00
범위 10:20:00 ~ 10:25:00 => 클라이언트 10:20:00 ~ 10:25:00
범위 10:25:00 - 10:30:00 => 클라이언트 없음 10:26:33 - 10:30:00
범위 10:30:00 - 10:35:00 => 10 : 30:33 ~ 10:33:42

스마트 쿼리를 만드는 것이 정말 어렵습니다. 01

select vo.timegoout as empty_start, min(vi.startentry) as empty_end 
from visits vo -- leave area (visit out) 
join visits vi -- enter area (visit in) 
    on vi.startentry > vo.timegoout 
where not exists (
    select * 
    from visits v 
    where v.timegoout > vo.timegoout 
     and v.startentry <= vo.timegoout 
) 
group by vo.timegoout 
union all 
select '00:00:00', (select min(startentry) from visits) 
union all 
select (select max(timegoout) from visits), '23:59:59' 
order by empty_start 

아이디어는 다음과 같습니다 : 아무도 지역에 없었다 때 23,

+0

2 가지 의견 : 범위 중 일부는 5 분 간격 이상을 다루고 데이터 세트에 주어진 범위가 표시되지 않으면 캘린더 테이블을 사용하여이 정보를 포함해야합니다. –

+0

일반적으로 데이터 표시 문제는 프레젠테이션 계층/응용 프로그램 수준 코드 (사용 가능한 경우)에서 가장 효과적으로 해결됩니다 (간단한 PHP 루프 – Strawberry

답변

1

다음 쿼리는 모든 시간을 반환합니다 범위는 누군가가 영역 (vo.timegoout as empty_start)을 떠나 때

지역은 비어 그 지역에 아무도 없다 (not exists (...)). 누군가 입력하기 전까지는이 영역이 비어 있습니다 (min(vi.startentry) as empty_end). 또한이 지역은 00:00:00에서 첫 번째 방문자가 에터스 (union all select '00:00:00', (select min(startentry) from visits))까지 비어 있습니다.마지막 방문자가 나뭇잎 후 또한 비어 우리는이 결과를 얻을 것이다

| startentry | timegoout | 
| 10:00:00 | 10:01:00 | 
| 10:10:10 | 10:11:11 | 
| 10:12:12 | 10:13:13 | 
| 12:33:33 | 12:55:55 | 
| 12:34:56 | 12:44:44 | 
| 14:31:00 | 14:33:00 | 
| 14:32:00 | 14:34:00 | 
| 16:00:00 | 16:10:00 | 

다음 샘플 데이터

을 감안할 때 23:59:59 ( union all select (select max(timegoout) from visits), '23:59:59')

까지 : 당신이 정확하려면

| empty_start | empty_end | 
| 00:00:00 | 10:00:00 | 
| 10:01:00 | 10:10:10 | 
| 10:11:11 | 10:12:12 | 
| 10:13:13 | 12:33:33 | 
| 12:55:55 | 14:31:00 | 
| 14:34:00 | 16:00:00 | 
| 16:10:00 | 23:59:59 | 

을 두 번째로 쿼리를 수정해야합니다.

select addtime(vo.timegoout, '00:00:01') as empty_start, 
     subtime(min(vi.startentry), '00:00:01') as empty_end 
from visits vo -- leave area (visit out) 
join visits vi -- enter area (visit in) 
    on vi.startentry > vo.timegoout 
where not exists (
    select * 
    from visits v 
    where v.timegoout > vo.timegoout 
     and v.startentry <= vo.timegoout 
) 
group by vo.timegoout 
union all 
select '00:00:00' as empty_start, (select subtime(min(startentry), '00:00:01') from visits) as empty_end from (select 1) dummy 
having empty_start <= empty_end 
union all 
select (select addtime(max(timegoout), '00:00:01') from visits) as empty_start, '23:59:59' as empty_end from (select 1) dummy 
having empty_start <= empty_end 
order by empty_start 

결과 :

| empty_start | empty_end | 
| 00:00:00 | 09:59:59 | 
| 10:01:01 | 10:10:09 | 
| 10:11:12 | 10:12:11 | 
| 10:13:14 | 12:33:32 | 
| 12:55:56 | 14:30:59 | 
| 14:34:01 | 15:59:59 | 
| 16:10:01 | 23:59:59 | 

가 처리 할 수있는 당신이 범위를 모두 포함하는 halper 테이블을 작성해야 5 분-범위 : 이제

| range_start | range_end | 
| 00:00:00 | 00:04:59 | 
| 00:05:00 | 00:09:59 | 
... 
| 23:50:00 | 23:54:59 | 
| 23:55:00 | 23:59:59 | 

다음 helper_5_minutes_ranges 테이블에

drop table if exists tmp_sequence; 
create table tmp_sequence (seq mediumint unsigned null); 

insert into tmp_sequence(seq) 
    values (null),(null),(null),(null),(null),(null),(null),(null),(null),(null); 

insert into tmp_sequence(seq) select seq from tmp_sequence; 
insert into tmp_sequence(seq) select seq from tmp_sequence; 
insert into tmp_sequence(seq) select seq from tmp_sequence; 
insert into tmp_sequence(seq) select seq from tmp_sequence; 
insert into tmp_sequence(seq) select seq from tmp_sequence; 

ALTER TABLE `tmp_sequence` 
    CHANGE COLUMN `seq` `seq` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT FIRST, 
    ADD PRIMARY KEY (`seq`); 

drop table if exists helper_5_minutes_ranges; 
create table helper_5_minutes_ranges(
    range_start time, 
    range_end time, 
    primary key (range_start, range_end) 
); 
insert into helper_5_minutes_ranges (range_start, range_end) 
    select sec_to_time((seq-1)*5*60) as range_start, sec_to_time((seq)*5*60-1) as range_end 
    from tmp_sequence ts 
    where ts.seq <= 288 
; 

drop table if exists tmp_sequence; 

데이터 다음과 같은 질문을 할 수 있습니다. 아무도이 지역에 없었을 때 5 분 전체 범위를 선택하십시오.

결과 : 누군가가 지역

select r.* 
from helper_5_minutes_ranges r 
join visits v 
    on v.startentry <= r.range_end 
    and v.timegoout >= r.range_start 

그리고 마침내이 괴물에왔다 때

| range_start | range_end | 
| 00:00:00 | 00:04:59 | 
... 
| 10:05:00 | 10:09:59 | 
| 10:15:00 | 10:19:59 | 
... 
| 12:25:00 | 12:29:59 | 
| 13:00:00 | 13:04:59 | 
... 
| 14:25:00 | 14:29:59 | 
| 14:35:00 | 14:39:59 | 
... 
| 15:55:00 | 15:59:59 | 
| 16:15:00 | 16:19:59 | 
... 
| 23:55:00 | 23:59:59 | 

이 예상 된 결과 같은 것을 반환하는 모든 5 분-범위를 선택

select r.*, 'visited' as type, 
    greatest(v.startentry, r.range_start) as vr_start, 
    least(v.timegoout, r.range_end) as vr_end 
from helper_5_minutes_ranges r 
join visits v 
    on v.startentry <= r.range_end 
    and v.timegoout >= r.range_start 

union all 

select mr.*, 'empty' as type, 
    greatest(er.empty_start, mr.range_start) as vr_start, 
    least(er.empty_end, mr.range_end) as vr_end 
from (
    select addtime(vo.timegoout, '00:00:01') as empty_start, 
      subtime(min(vi.startentry), '00:00:01') as empty_end 
    from visits vo -- leave area (visit out) 
    join visits vi -- enter area (visit in) 
     on vi.startentry > vo.timegoout 
    where not exists (
     select * 
     from visits v 
     where v.timegoout > vo.timegoout 
      and v.startentry <= vo.timegoout 
    ) 
    group by vo.timegoout 
    union all 
    select '00:00:00' as empty_start, (select subtime(min(startentry), '00:00:01') from visits) as empty_end from (select 1) dummy 
    having empty_start <= empty_end 
    union all 
    select (select addtime(max(timegoout), '00:00:01') from visits) as empty_start, '23:59:59' as empty_end from (select 1) dummy 
    having empty_start <= empty_end 
) er 
join helper_5_minutes_ranges mr 
    on mr.range_start <= er.empty_end 
    and mr.range_end >= er.empty_start 

order by range_start, vr_start 

결과 :

| range_start | range_end | type | vr_start  | vr_end   | 
... 
| 09:55:00 | 09:59:59 | empty | 09:55:00.000000 | 09:59:59.000000 | 
| 10:00:00 | 10:04:59 | visited | 10:00:00.000000 | 10:01:00.000000 | 
| 10:00:00 | 10:04:59 | empty | 10:01:01.000000 | 10:04:59.000000 | 
| 10:05:00 | 10:09:59 | empty | 10:05:00.000000 | 10:09:59.000000 | 
| 10:10:00 | 10:14:59 | empty | 10:10:00.000000 | 10:10:09.000000 | 
| 10:10:00 | 10:14:59 | visited | 10:10:10.000000 | 10:11:11.000000 | 
| 10:10:00 | 10:14:59 | empty | 10:11:12.000000 | 10:12:11.000000 | 
| 10:10:00 | 10:14:59 | visited | 10:12:12.000000 | 10:13:13.000000 | 
| 10:10:00 | 10:14:59 | empty | 10:13:14.000000 | 10:14:59.000000 | 
... 
+0

우수! 작동이 매우 좋음). 그냥 range_end 비트를 변경합니다. – sontd