mysql连接条件 - 根据自定义顺序

时间:2017-05-06 18:50:52

标签: mysql sql inner-join

对于糟糕的头衔感到抱歉,但很难用一行来解释。

我有一个窗口小部件数据表 - 每个记录都有一个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的最新官方记录(应该忽略官方记录之后的任何预备记录)

目前,我正在使用此查询:

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

此查询为我提供了按设备和状态分组的最新行,因此在设备B的情况下,它返回2行 - 而不是我需要的行。

如何限制联接仅返回官方行(如果存在)。我觉得我应该能够通过内部查询的位置或者join子句中的coalesce()解决这个问题,但是我不能完全围绕它解决这个问题。

感谢。

2 个答案:

答案 0 :(得分: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子句中使用。

答案 1 :(得分: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)