SQL: выбор уникальных строк с минимальным значением
Быстрый ответ
Если вам требуется быстрый результат, используйте функцию MIN()
в сочетании с GROUP BY
и выполните соединение с исходной таблицей. Допустим, у нас есть таблица orders
, в которой необходимо отобразить заказ с самой низкой стоимостью для каждого изделия:
SELECT o1.product_id, o1.price
FROM orders o1
JOIN (
SELECT product_id, MIN(price) AS min_price
FROM orders
GROUP BY product_id
) o2 ON o1.product_id = o2.product_id AND o1.price = o2.min_price;
??Другими словами для тех, кто только начинает изучать SQL: мы выбираем изделие с самой низкой ценой из всех предложенных вариантов.
Подробнее о оконных функциях
Применение функции ROW_NUMBER()
Функция ROW_NUMBER()
в SQL действует как волшебная палочка. Она способна выполнять чудеса, когда используется вместе с OVER
и PARTITION BY
:
SELECT product_id, price
FROM (
SELECT product_id,
price,
ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY price ASC) AS rn
FROM orders
) ranked
WHERE rn = 1;
DISTINCT ON – ваш выбор в PostgreSQL
Если вы используете PostgreSQL и цените ясность и краткость, DISTINCT ON
станет для вас надёжным помощником:
SELECT DISTINCT ON (product_id) product_id, price
FROM orders
ORDER BY product_id, price ASC;
Проверенное временем применение подзапросов
Когда возникают сомнения, вы можете прибегнуть к подзапросам. Этот метод надёжен и проверен временем, подобно старому доброму гномику садовому:
SELECT *
FROM orders o1
WHERE price = (
SELECT MIN(price)
FROM orders o2
WHERE o1.product_id = o2.product_id
);
Управление несколькими группировками как профессионал
Группировка по нескольким критериям
Когда приходится группировать по нескольким столбцам, например, id
и game
, важно выбрать правильную стратегию использования GROUP BY
:
SELECT o1.id, o1.game, o1.point
FROM scores o1
JOIN (
SELECT id, game, MIN(point) AS min_point
FROM scores
GROUP BY id, game
) o2 ON o1.id = o2.id AND o1.game = o2.game AND o1.point = o2.min_point;
FIRST_VALUE для выбора первых значений
Время от времени требуется извлечь первое значение из группы. SQL предоставляет такую возможность с помощью FIRST_VALUE
:
SELECT DISTINCT id, game,
FIRST_VALUE(point) OVER (PARTITION BY id, game ORDER BY point ASC) AS min_point
FROM scores;
Визуализация
Давайте представим, что у нас есть конкурс фотографий, где от каждого участника принимается к рассмотрению только его лучшая работа с низким баллом. Теперь переведем это на язык SQL:
| Фотограф | Заявка # | Баллы |
| ---------- | -------- | -------- |
| Алиса | 1 | 37 |
| Боб | 2 | 29 |
| Чарли | 3 | 22 |
| Алиса | 4 | **14** |
| Боб | 5 | **15** |
| Чарли | 6 | **20** |
Применив запрос:
SELECT DISTINCT ON (photographer) *
FROM entries
ORDER BY photographer, score ASC;
Мы получим итоги:
| Фотограф (📷) | Лучший снимок (🏆) |
| ------------- | ------------------ |
| Алиса | 14 |
| Боб | 15 |
| Чарли | 20 |
Таким образом, мы увидим только лучшие работы 🥇 от каждого участника.
Устранение распространённых проблем
Значимость времени выполнения
Никогда не забывайте о времени выполнения запроса ⏰, особенно при работе с большими объемами данных. В таких случаях JOIN
и подзапросы могут занять значительное время.
Особенности диалектов SQL
Всегда проверяйте совместимость 😎 ваших запросов, так как разные диалекты SQL имеют свои особенности.
Обработка ситуаций с одинаковыми значениями
Когда в данных возникает ситуация ничьей 🤼, добавьте в ORDER BY
дополнительные столбцы для однозначной сортировки.
Полезные материалы
Для улучшения ваших навыков работы с SQL рекомендуем ознакомиться со следующими материалами 📚: