Выберите строки и удалите дубликаты на основе значения столбца

#sql #postgresql #select #duplicates

#sql #postgresql #выберите #дубликаты

Вопрос:

У меня есть следующий запрос:

 select "houses"."id", 
"houses"."uuid", 
COUNT(1) OVER() as full_count from "houses" 
CROSS JOIN LATERAL jsonb_array_elements(houses.types) house_types 
inner join "hoods" on "hoods"."id" = "houses"."hood_id" and "hoods"."owner_id" = 2 
inner join "groups" on "groups"."hood_id" = "hoods"."id" and "groups"."manager_id" = 54 
where house_types->>'type' = 'big' 
group by "houses"."id", "houses"."uuid" 
order by lower(houses.name) asc 
limit 20
  

Который правильно выдает мне первые 20 домов с типом ‘big’, которые находятся в блоке, идентификатор владельца которого равен 2, И с которым в блоке связана группа, менеджер которой равен 54.

Теперь проблема в том, что иногда у меня будут дома, название которых будет одинаковым, и я хочу просто сохранить один из них и удалить остальные. Так, например:

Если моя таблица домов выглядит как:

 id, types, name
1, [{ type: 'rating' }], 'white house'
2, [{ type: 'rating' }], 'white house'
3, [{ type: 'rating' }], 'red house'
  

Я бы просто получил строки с идентификаторами 1 и 3.

Какой хороший способ сделать это в PostgreSQL, предполагая, что к запросу могут применяться как смещения, так и ограничения, и я хочу удалить дубликаты.

Ответ №1:

Вместо group by используйте distinct on :

 select distinct on (lower(h.name)) h.id, h.uuid
      COUNT(*) OVER() as full_count
from houses h cross join lateral
     jsonb_array_elements(h.types) ht inner join
     "hoods" ho
     on ho.id = h.hood_id and
        ho.owner_id = 2 inner join
     "groups" g
     on g.hood_id = ho.id and
        g.manager_id = 54 
where house_types->>'type' = 'big' 
order by lower(houses.name) asc  
limit 20;
  

Редактировать:

 select h.*, count(*) over ()  as full_count
from (select distinct on (lower(h.name)) h.id, h.uuid
      from houses h cross join lateral
           jsonb_array_elements(h.types) ht inner join
           "hoods" ho
           on ho.id = h.hood_id and
              ho.owner_id = 2 inner join
           "groups" g
           on g.hood_id = ho.id and
              g.manager_id = 54 
      where house_types->>'type' = 'big' 
      order by lower(houses.name) asc  
     ) h
limit 20
  

Комментарии:

1. Спасибо, Гордон. Зачем вам оба нижних (h.name ) и h.id и разместите.uuid в DISTINCT ВКЛ., если мы просто хотим, чтобы они различались по имени?

2. @HommerSmith . , , Я думаю, вы правы. Это не требуется.

3. Гордон, с этим подходом есть проблема. Несмотря на то, что distinct ON работает, COUNT(*) OVER() все еще считает удаленные строки. Как я могу получить как distinct, так и подсчитать все результаты, используя функцию window, чтобы я мог правильно знать все потенциальные уникальные строки, которые существуют помимо limit?

4. @HommerSmith . . . Я бы рекомендовал подзапрос с distinct on , чтобы уменьшить количество строк. Затем используйте count() функцию window.

5. Что вы имеете в виду подзапрос с DISTINCT ON? Я думал о том, чтобы на самом деле создать подзапрос, который выполнял бы ПОДСЧЕТ. Вы не возражаете расширить свой ответ?