Выборка первых записей по уникальным значениям в MySQL
Пройдите тест, узнайте какой профессии подходите
Быстрый ответ
Выбор строк с первым появлением каждого уникального значения можно реализовать путём использования самосоединения с фильтрацией по минимальному id
:
SELECT t1.*
FROM your_table AS t1
JOIN (
SELECT MIN(id) AS MinId
FROM your_table
GROUP BY unique_column
) AS t2 ON t1.id = t2.MinId;
Здесь минимальное значение id
обеспечивает выбор первого встречающегося элемента, а GROUP BY unique_column
гарантирует уникальность значений. Этот подход простой и эффективный для быстрой реализации такой задачи.
Магия оконных функций: Продвинутый подход
Начиная с MySQL 8, оконные функции стали ещё одним способом упростить наши запросы и сделать их более эффективными:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY unique_column ORDER BY sorting_column) AS rn
FROM your_table
) AS sub
WHERE sub.rn = 1;
Функция ROW_NUMBER()
пронумеровывает строки внутри группы, определённой unique_column
, и выбирает первую строку каждой группы.
Существующие ограничения MySQL: Реальность
При работе с негруппированными колонками следует помнить об агрегатных функциях и включении полей в GROUP BY
. В противном случае MySQL может пренебречь нарушением стандартов SQL, возвращая непредсказуемые результаты.
Распространенные ошибки и как их избежать: Чего не стоит делать
Использование MAX()
в целях поиска первых уникальных значений является нелогичным, поскольку данная функция возвращает последний элемент. В таком случае лучше использовать MIN()
.
Визуализация
Давайте визуализируем это. Представим таблицу базы данных в виде участников гонки, где у каждого уникального значения есть своя эстафетная палочка 👟:
🏁: [🏃♂️7️⃣, 🏃♂️5️⃣, 🏃♂️3️⃣, 🏃♂️7️⃣, 🏃♂️5️⃣, 🏃♀️2️⃣]
Задача MySQL – выбрать первого бегуна для каждой палочки:
SELECT * FROM runners WHERE baton = FIRST_OCCURRENCE;
И вот наши призёры:
🥇: [🏃♂️7️⃣, 🏃♂️5️⃣, 🏃♂️3️⃣, 🏃♀️2️⃣]
Среди призёров нет повторов – по одной строке для каждой уникальной записи!
Продвинутые запросы для умных решений
Если требуется всё содержимое строки, а не просто id
, то следует использовать соединение с подзапросом:
SELECT t1.*
FROM your_table AS t1
INNER JOIN (
SELECT unique_column, MIN(time) AS MinTime
FROM your_table
GROUP BY unique_column
) AS t2 ON t1.unique_column = t2.unique_column AND t1.time = t2.MinTime;
Сценарии применения в реальной жизни
Этот метод подойдёт для различных целей:
- Поиск первой покупки каждого клиента.
- Определение времени первого входа в систему пользователем.
- Получение первых данных от датчиков каждого устройства.
Важность производительности: Оптимизация ваших запросов
Чтобы увеличить скорость и эффективность ваших запросов, особенно при работе с большими объёмами данных, убедитесь, что все колонки в JOIN
, WHERE
и ORDER BY
проиндексированы. Правильная индексация делает запросы быстрыми и эффективными.
Полезные материалы
- MySQL :: Руководство по MySQL 8.0 :: 14.19.3 Обработка GROUP BY в MySQL — Подробный разбор работы с
GROUP BY
. - PostgreSQL DISTINCT ON with different ORDER BY – Stack Overflow — Обсуждение подхода к выборке уникальных строк в PostgreSQL.
- MySQL :: Руководство по MySQL 8.0 :: 14.20 Оконные функции — Детальное описание синтаксиса и использования оконных функций.
- Fetch the rows which have the Max value for a column for each distinct value of another column – Stack Overflow — Обсуждение использования соединений для отбора уникальных значений.
- SQL Indexing and Tuning e-Book for developers: Use The Index, Luke — Рекомендации по оптимизации SQL запросов через индексирование.
- SQL GROUP BY | Intermediate SQL – Mode — Глубокий дайв в
GROUP BY
в SQL.