DISTINCT ON: Как выбирать нужное, не нумеруя лишнего
В SQL есть стандартный DISTINCT, который используется так: SELECT DISTINCT names FROM table. Это означает: «Дай мне все УНИКАЛЬНЫЕ имена из таблицы».
Представим, что в коробке лежат джинсы, футболки и кепки. Запрос SELECT DISTINCT clothes выдаст по одному экземпляру от каждого вида: одни джинсы, одну футболку и одну кепку.
Добавив описательные атрибуты, например, DISTINCT clothes, color мы получим уникальные комбинации вида и цвета.Теперь мы можем достать по одной футболке зеленого и желтого цвета, но нам может попасться хлопковая, кашемировая или шелковая. Если мы хотим достать по одной штуке каждого вида, цвета и материала, мы напишем DISTINCT clothes, color, material — в общем, перечислим всё, что должно входить в уникальный набор.
Эту фишку можно продвинуть и использовать DISTINCT ON.
Мы пишем: DISTINCT ON (clothes, color, material) и добавляем ORDER BY, например, по price. С помощью DISTINCT ON мы указываем, по каким столбцам определять уникальность, а сортировкой (в данном случае по цене) просто забираем самую дорогую вещь в этой категории.
Это хорошая альтернатива оконной функции ROW_NUMBER(). Обычно мы нумеруем список, а потом берем строки, где rn = 1. В таком случае оконка проходит по всей таблице, нумерует каждую строку, а потом выбирает нужное. DISTINCT ON работает иначе: мы задаем набор, сортируем его и сразу берем первую строку из каждой группы. Это сильно ускоряет и оптимизирует процесс. Пример из другой части гардероба — выбираем кроссовки в магазине:
Обычный DISTINCT — просим продавца: «Покажи мне бренды, какие есть у вас в наличии». Он приносит одну коробку Nike, одну Adidas и одну Jordan.
ROW_NUMBER() — это если бы мы заставили продавца вынести из подсобки ВООБЩЕ ВСЕ кроссовки Nike, расставить их по цене от дорогих к дешевым, наклеить на каждую коробку порядковый номер и только потом отдать вам ту, что под номером один.
DISTINCT ON — это когда мы говорим: «Из каждого бренда принеси мне только самую дорогую пару». Продавец сразу идет к полке, берет топовую модель и не тратит время на перекладывание всего склада.
Результат тот же, но действий в разы меньше. Важный нюанс: работает DISTINCT ON только в PostgreSQL. Связи: 📌 Кстати, напоминает те самые «стопки книг», про которые писал в заметке про LATERAL. Но есть отличия — об этом в других постах.
В этом посте были ссылки, но мы их удалили по правилам Сетки