#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? Я думал о том, чтобы на самом деле создать подзапрос, который выполнял бы ПОДСЧЕТ. Вы не возражаете расширить свой ответ?