对一组选择中的一个值进行 DISTINCT

DISTINCT on one value from a group selects

我有以下sql查询

select devices_device.id , devices_device.code, sss.id as "site_id", sss.name as "site_name"
from devices_device
inner join st_site_site sss on devices_device.site_id = sss.id
where devices_device.deleted = false
order by devices_device.id, devices_device.start_date

我现在获得了设备 ID 列表。其中一些是相同的。我想做一个不同的,所以我只保留每个设备的第一条记录(并且由于 start_date 上的排序,这将是该设备的最新设备记录)

我该怎么做?如果我这样做

select distinct devices_device.id , devices_device.code, sss.id as "site_id", sss.name as "site_name"
from devices_device
inner join st_site_site sss on devices_device.site_id = sss.id
where devices_device.deleted = false
order by devices_device.id, devices_device.start_date

什么都没发生

您或许应该使用 GROUP BY。类似于:

select distinct devices_device.id , devices_device.code, sss.id as "site_id", 
sss.name as "site_name"
from devices_device
inner join st_site_site sss on devices_device.site_id = sss.id
where devices_device.deleted = false
group by devices_device.id
order by devices_device.start_date

您可以使用ROW_NUMBER() window 函数来确定您想要的行。然后过滤掉其他的就很容易了。

例如:

select *
from (
  select
    d.id, d.start_date, d.code, 
    s.id as "site_id", s.name as "site_name", 
    row_number() over(partition by d.id order by start_date desc) as rn
  from devices_device d
  inner join st_site_site s on d.site_id = s.id
  where d.deleted = false
) x
where rn = 1
order by id, start_date

在此查询中,每个设备组中最新行的 ROW_NUMBER() 值将为 1。这就是最后的过滤如何删除大于 1.

的所有其他行

注意:如果有冲突(两行具有相同的最近 start_date),此查询将始终 return a 单行 [虽然是随机的] 他们之间的行。

您可以测试最短开始日期

drop table if exists devices_device,st_site_site;
create table devices_device(id int,code int,site_id int,start_date date,deleted int);
create table st_site_site(id int,name varchar(10));
insert into devices_device values(1,10,1,'2020-10-01',0),(1,20,1,'2020-09-01',0);
insert into st_site_site values(1,'aaa');

select devices_device.id , devices_device.code, sss.id as "site_id", sss.name as "site_name"
from devices_device
inner join st_site_site sss on devices_device.site_id = sss.id
where devices_device.deleted = false and
        devices_device.start_date = (select min(d1.start_date) from devices_device d1 where d1.id = devices_device.id)
order by devices_device.id;

+------+------+---------+-----------+
| id   | code | site_id | site_name |
+------+------+---------+-----------+
|    1 |   20 |       1 | aaa       |
+------+------+---------+-----------+
1 row in set (0.001 sec)