2017-05-06 6 views
3

불쌍한 제목에 대해 유감이지만 한 줄로 설명하기가 어렵습니다.mysql 조인 조건 - 사용자 정의 순서에 따라 그룹의 단일 행으로 조인 제한

각 레코드에는 ID, 생성 된 타임 스탬프, device_id (외부 키) 및 상태 ('prelim'또는 'official')가있는 위젯 데이터 테이블이 있습니다. 각 장치에 대해 가장 최신의 "가장 공식적인"단일 레코드를 얻으려고합니다. 즉, 가장 최근의 공식 레코드가 필요하지만 공식적인 레코드가 없으면 가장 새로운 공식 레코드입니다. 예

ID | created | device_id | status | data 
1 | 100  | A   | prelim | ## 
2 | 105  | A   | prelim | ## 
3 | 107  | B   | official | ## 
4 | 109  | B   | prelim | ## 

는 공식적인 기록이 없기 때문에 나는 행 2를 얻어야한다, 그리고 최신 장치 A에 대한 기록 및 행 3은 장치 B에 대한 최신 공식 기록 (공식 후 모든 예선 기록이 있기 때문에 하나는 무시되어야 함).

현재, 나는이 쿼리를 사용하고 있습니다 : - 내가 필요하지 어떤 장치 B의 경우에, 그래서

Select widget.* from widget 
INNER JOIN (select id, device_id, status, max(created) as created from widget 
     group by device_id, status) max_widget 
    on widget.created = max_widget.created and widget.device_id = max_widget.device_id 

이 쿼리 나에게 장치 및 상태별로 그룹화 최신 행을 제공을,이 2 개 행을 반환 .

공식 행만 존재할 경우 참여를 제한하도록 어떻게 제한 했습니까? 내부 쿼리 또는 join 절에서 coalesce()를 사용하여이 문제를 해결할 수 있어야한다고 생각합니다. 그러나 주변에서 내 머리를 감쌀 수는 없습니다.

감사합니다.

답변

2

당신은 이것에 대한 상관 하위 쿼리를 사용할 수 있습니다

select * 
from widget w 
where id = (
     select id 
     from widget x 
     where w.device_id = x.device_id 
     order by field(status, 'official', 'prelim'), created desc 
     limit 1 
     ); 

order by field(status, 'official', 'prelim')은 최초의 "공식"기록을 유지하고 created desc는 먼저 최신 사람을 유지합니다. limit 1은 where 절에서 사용할 수있는 행 하나를 가져옵니다.

+2

가 나는 상태 주문에 대한 명시적인 것 (필드로 말하자면, 사용,'순서 (상태, '공식',') '예선') 그러나 이것은 좋은 해결책. –

+0

과거 성능 문제로 인해 상관 관계가있는 하위 쿼리에서 멀리 떨어지는 경향이 있지만 문제가 해결됩니다. 위젯의 모든 단일 행에 대해 하위 쿼리를 실행하여 일치 여부를 확인하지 않아도됩니까? – whiteatom

+1

@whiteatom. . . 사실 위젯 (device_id, status, created, id)에 대한 색인을 가진 Gurwinders 솔루션은 좋은 성능을 가져야합니다. –

0
create table widget (
    id smallint, 
    created smallint, 
    device_id char(1), 
    status varchar(20), 
    data varchar(20)); 

insert into widget (id, created, device_id, status, data) values (1,100,'A','prelim','abcd1234'); 
insert into widget (id, created, device_id, status, data) values (2,105,'A','prelim','efgh5678'); 
insert into widget (id, created, device_id, status, data) values (3,107,'B','official','ijkl9012'); 
insert into widget (id, created, device_id, status, data) values (4,109,'B','prelim','mnop3456'); 


select max(a.created), 
     a.device_id, 
     case 
      when b.id is null 
      then a.status 
      else b.status 
     end as status 
from widget a 
left join widget b 
    on a.device_id = b.device_id 
    and b.status = 'official' 
where (
     (a.status = 'prelim' 
      and b.status is null) 
     or 
     (b.status = 'official' 
      and a.status <> 'prelim') 
    ) 
group by a.device_id, 
     case 
      when b.id is null 
      then a.status 
      else b.status 
     end; 

출력 :

+----------------+-----------+----------+ 
| max(a.created) | device_id | status | 
+----------------+-----------+----------+ 
|   105 | A   | prelim | 
|   107 | B   | official | 
+----------------+-----------+----------+ 
2 rows in set (0.00 sec) 
+0

필자가 필요한 것은 아니지만, 나는 100 번째 줄에 기록을 남기지 말아야한다. – whiteatom

+0

죄송합니다. 결과를 집계 할 수 있다는 의미입니다.이 답변은 하위 쿼리를 사용하지 않습니다. 답변을 수정하겠습니다. –