2014-07-11 2 views
2

다음과 같은 문제를 해결하기 위해 노력하고 있습니다. 매분마다 위치와 온라인 상태를 업데이트하는 추적 장치가 있습니다. 온라인 상태를 select 문에서 여러 개의 작은 하위 집합으로 그룹화하여이 데이터를 별도의 여행으로 분할하려고합니다.하위 그룹의 최소값 및 최대 값 선택 방법

최소 &을 선택할 수 있다는 것을 알고 있습니다. 테이블 전체에 대해이 최대 값과 합집합을 사용할 수 있지만 온라인 상태가 참인 각 그룹에 대해이를 수행하는 방법을 잘 모르겠습니다.

코드에서 원하는 결과를 얻을 수 있지만 전선 성능상의 이유로이 작업을 서버로 옮겨야합니다.

누구든지 올바른 방향으로 SQL 문을 분해 할 수 있습니까?

[positions] 
+-------------------+-----------------------+------+-----+---------+----------------+ 
| Field    | Type     | Null | Key | Default | Extra   | 
+-------------------+-----------------------+------+-----+---------+----------------+ 
| id    | int   unsigned | NO | PRI | NULL | auto_increment | 
| device_id   | int   unsigned | NO |  | NULL |    | 
| lat    | double    | NO |  | 0  |    | 
| lng    | double    | NO |  | 0  |    | 
| date_time   | datetime    | NO |  | NULL |    | 
| online   | bit     | NO |  | 0  |    | 
+-------------------+-----------------------+------+-----+---------+----------------+ 

예 데이터

id device_id lat  lng  date_time    online 
14 1   0.1  0.1  2014-07-11 05:21:37 0 
17 1   0.11 0.11 2014-07-11 05:22:37 1 
18 1   0.12 0.12 2014-07-11 05:23:37 1 
24 1   0.13 0.13 2014-07-11 05:24:37 1 
25 1   0.14 0.14 2014-07-11 05:25:37 1 
26 1   0.14 0.14 2014-07-11 05:26:37 0 
45 1   0.14 0.14 2014-07-11 05:27:37 0 
47 1   0.14 0.14 2014-07-11 05:28:37 1 
56 1   0.13 0.13 2014-07-11 05:29:37 1 
67 1   0.12 0.12 2014-07-11 05:30:37 1 
68 1   0.11 0.11 2014-07-11 05:31:37 1 
78 1   0.11 0.11 2014-07-11 05:32:37 0 

원하는 결과를 사전에

StartDateTime  StartLat StartLng FinishDateTime  FinishLat FinishLng 
2014-07-11 05:22:37 0.11  0.11  2014-07-11 05:25:37 0.14  0.14 
2014-07-11 05:28:37 0.14  0.14  2014-07-11 05:31:37 0.11  0.11 

감사합니다, 스티브

+0

는 그 일반적인 경우, 장치 ID = 1의 ID 번호에 갭이있는 이유는 한번에 활성 한 기기 ID보다 더있을 수 가정 공정인가? –

+0

맞습니다. 조나단 –

답변

1

는 각 그룹의 특성을해야합니다. 가장 쉬운 방법은 각 행하기 전에 online = 0의 수를 계산하는 것입니다

select device_id, min(date_time) as StartDateTime, max(date_time) as FinishDateTime, 
     substring_index(group_concat(lat order by datetime asc), ',', 1) as StartLat, 
     substring_index(group_concat(long order by datetime asc), ',', 1) as StartLong, 
     substring_index(group_concat(lat order by datetime desc), ',', 1) as EndLat, 
     substring_index(group_concat(long order by datetime desc), ',', 1) as EndLong 
from (select e.*, 
      (select count(*) 
       from example e2 
       where e2.device_id = e.device_id and 
        e2.date_time <= e.date_time and 
        e2.online = 0 
      ) as grp 
     from example e 
     where e.online = 1 
    ) e 
group by device_id, grp; 

이 처음과 마지막 값을 얻기 위해 substring_index()/group_concat() 트릭을 사용합니다.

select t.*, 
     efirst.lat as firstLat, efirst.long as firstLong, 
     ellast.lat as lastLat, elast.long as lastLong 
from (select device_id, min(date_time) as StartDateTime, max(date_time) as FinishDateTime 
     from (select e.*, 
        (select count(*) 
        from example e2 
        where e2.device_id = e.device_id and 
          e2.date_time <= e.date_time and 
          e2.online = 0 
        ) as grp 
      from example e 
      where e.online = 1 
      ) e 
     group by device_id, grp 
    ) t join 
    example efirst 
    on efirst.device_id = t.device_id and efirst.date_time = FirstDateTime join 
    example elast 
    on elast.device_id = t.device_id and elast.date_time = FinishDateTime; 
+0

감사합니다. Gordon, 응답을 더 잘 이해하기 위해 하위 문자열 및 그룹 concat을 살펴 봅니다. –

+0

@StephenManderson. . . 'device_id'와'datetime'에 원래의 테이블에 다시 합쳐서 첫 번째와 마지막 좌표를 얻을 수 있습니다; 이미 aggregation을 할 때'substring_index()'/'group_concat()'트릭을 쉽게 찾을 수 있습니다. –

+0

당신이 제안하는 두 가지 방법으로 성능에 많은 차이가 있다는 것을 알고 있습니까? 그건 위의 솔루션과 함께, 나는 원래의 유형으로 다시 BLOB 값을 캐스팅해야합니다. 또는 조인 비용을 더 많이 사용합니까? –

관련 문제