DISTINCT по одному значению из группы выбирает - PullRequest
0 голосов
/ 05 августа 2020

У меня следующий 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

Теперь я получаю список идентификаторов устройств. Некоторые из них такие же. Я хочу сделать отдельную запись, поэтому я сохраняю только первую запись для каждого устройства (и из-за порядка 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

, ничего не произойдет

Ответы [ 3 ]

1 голос
/ 05 августа 2020

Вы можете использовать функцию окна ROW_NUMBER() для определения нужной строки. Тогда отфильтровать остальные легко.

Например:

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) этот запрос всегда будет возвращать a одиночный [хотя и случайный] ряд между ними.

0 голосов
/ 05 августа 2020

Вы можете проверить минимальную дату начала

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)
0 голосов
/ 05 августа 2020

Вероятно, вам следует использовать 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
...