Это часть 3 из 10 учебника «SQL с нуля для аналитика». Содержание серии в конце поста. ← Часть 2
TL;DR: ORDER BY сортирует результат (ASC по возрастанию по умолчанию, DESC по убыванию). LIMIT N берёт только первые N строк. OFFSET N пропускает первые N. DISTINCT оставляет только уникальные значения. Эти 4 ключевых слова решают типичные задачи: «топ-10 покупателей», «уникальные страны», «вторая страница».
В этой части:
- Сортировка через ORDER BY (ASC, DESC)
- Сортировка по нескольким колонкам
- LIMIT для ограничения количества
- OFFSET для пагинации
- DISTINCT для уникальных значений
Как отсортировать результат?
ORDER BY сортирует строки:
-- По возрастанию (по умолчанию)
SELECT email, created_at
FROM users
ORDER BY created_at;
-- По убыванию (новейшие сверху)
SELECT email, created_at
FROM users
ORDER BY created_at DESC;
ASC = ascending (по возрастанию), DESC = descending (по убыванию). Без указания — ASC.
Как сортировать по нескольким колонкам?
Перечисли колонки через запятую. Сначала сортируется по первой, потом по второй внутри одинаковых значений:
-- Сначала по стране (по алфавиту), потом по выручке (от большей)
SELECT country, user_id, revenue
FROM users_revenue
ORDER BY country ASC, revenue DESC;
Результат: внутри каждой страны — топ-выручка сверху.
Как взять только первые N строк?
LIMIT N ограничивает количество результата:
-- Топ-10 покупателей по выручке
SELECT user_id, SUM(amount) AS total
FROM orders
GROUP BY user_id
ORDER BY total DESC
LIMIT 10;
(GROUP BY разберём в Части 4).
LIMIT без ORDER BY возвращает любые N строк (порядок не гарантирован). Это частая ошибка.
Например, типичные топ-N кейсы аналитика: топ-10 продуктов по выручке, топ-50 клиентов по LTV, топ-5 каналов с худшей конверсией. Все через ORDER BY metric DESC LIMIT N.
Как делать пагинацию?
OFFSET N пропускает первые N строк:
-- Первая страница (10 строк)
SELECT email FROM users ORDER BY id LIMIT 10 OFFSET 0;
-- Вторая страница (строки 11-20)
SELECT email FROM users ORDER BY id LIMIT 10 OFFSET 10;
-- Третья страница (21-30)
SELECT email FROM users ORDER BY id LIMIT 10 OFFSET 20;
Формула: OFFSET = (page - 1) * page_size.
Подвох: OFFSET медленный на больших таблицах. БД всё равно читает первые OFFSET строк, потом отбрасывает. Для page 1000 на 10М-таблице — секунды. Альтернатива — keyset pagination (через WHERE по id), но это уже advanced. Подробнее в SQL antipatterns.
Как получить уникальные значения?
DISTINCT оставляет только уникальные строки:
-- Все страны, в которых есть пользователи
SELECT DISTINCT country FROM users;
-- Уникальные пары (страна, статус)
SELECT DISTINCT country, status FROM orders;
DISTINCT работает по всем выбранным колонкам, не только по первой.
Типичный случай: после миграции с MS SQL на PostgreSQL обнаруживаются дубли user_id в events (legacy session-tracking генерировал случайные UUID). SELECT DISTINCT user_id показывает реальное количество уникальных пользователей.
DISTINCT vs GROUP BY — что выбрать?
Они часто дают одинаковый результат:
-- Эквивалентны
SELECT DISTINCT country FROM users;
SELECT country FROM users GROUP BY country;
Разница:
| Критерий | DISTINCT | GROUP BY |
|---|---|---|
| Простой случай | Короче | Многословнее |
| Нужны агрегаты (COUNT, SUM) | Не работает | Идеально |
| Performance | Чаще равны | Иногда быстрее |
Правило: для простых уникальных — DISTINCT. Для агрегатов — GROUP BY. Подробнее GROUP BY в Части 4.
Какие 4 типичные ошибки с ORDER BY и LIMIT?
- Ошибка 1:
LIMIT 10безORDER BY. Порядок не гарантирован — каждый раз разные строки. - Ошибка 2:
ORDER BY 1(по индексу колонки). Работает, но плохо читается. Лучше явноORDER BY created_at. - Ошибка 3: Большой OFFSET. На 1М строк
OFFSET 100000— секунды. Используй keyset pagination для production. - Ошибка 4: NULL-значения сортируются по-разному в PG/MySQL. PG: NULL последний (DESC) или первый (ASC). MySQL: наоборот. Явно укажи
NULLS FIRST/NULLS LAST.
SELECT user_id, last_login
FROM users
ORDER BY last_login DESC NULLS LAST;
Частые вопросы про ORDER BY, LIMIT, DISTINCT
Как взять случайную строку?
ORDER BY RANDOM() LIMIT 1 (PG) или ORDER BY RAND() LIMIT 1 (MySQL). Медленно на больших таблицах — БД сортирует всё, потом берёт 1. Для production — TABLESAMPLE.
Что такое NULLS FIRST / NULLS LAST?
Управление порядком NULL в результате. PostgreSQL default: NULL последние при ASC, первые при DESC. Явно: ORDER BY col ASC NULLS FIRST.
Можно ли в LIMIT использовать переменную?
В standalone SQL — нет. В коде приложения (Python/JS) — да, через параметризацию. В dbt — через Jinja {{ var('page_size') }}.
LIMIT 0 — что вернёт?
Пустой результат, но БД всё равно подготавливает план. Иногда используется для проверки схемы запроса без исполнения. Лучше EXPLAIN для этого.
DISTINCT медленнее GROUP BY?
В современных PG/CH — обычно равны. Оптимизатор для DISTINCT по сути делает GROUP BY под капотом.
Что дальше?
В Части 4 — самая важная часть для аналитика: агрегатные функции (COUNT, SUM, AVG, MIN, MAX) и GROUP BY. Без этого никаких метрик не посчитать.
Сейчас открой SQL-тренажёр — попробуй написать запрос «топ-5 пользователей по выручке» с ORDER BY + LIMIT.
В Pro — безлимит мок-собесов на AI-интервью + 491 SQL-задача + 612 тестовых заданий + 50+ блог-постов.
Навигация по учебнику
← Часть 2 | Часть 3: ORDER BY, LIMIT, DISTINCT | Часть 4 →
Содержание серии: 1 · 2 · 3 · 4 · 5 · 6 · 7 · 8 · 9 · 10
Источники
- PostgreSQL Docs: «Sorting Rows» (postgresql.org/docs/current/queries-order.html)
- PostgreSQL Docs: «LIMIT and OFFSET» (postgresql.org/docs/current/queries-limit.html)