Ответ
Задача "топ-N" решается комбинацией сортировки (ORDER BY) и ограничения количества строк (LIMIT). Вот как я это делаю в разных сценариях.
Базовый случай: простой топ по значению поля
-- Топ-5 самых дорогих товаров
SELECT id, name, price
FROM products
ORDER BY price DESC
LIMIT 5;
-- Топ-3 последних зарегистрированных пользователя
SELECT id, name, created_at
FROM users
ORDER BY created_at DESC
LIMIT 3;
Сложные сценарии:
1. Топ внутри групп (аналог ROW_NUMBER())
Допустим, нужен самый дорогой товар в каждой категории. В старых версиях MySQL можно использовать переменные или подзапросы, но современный способ — оконные функции.
-- Используем оконную функцию (MySQL 8.0+, PostgreSQL, SQL Server)
SELECT * FROM (
SELECT
id, name, category_id, price,
ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY price DESC) as rank_in_category
FROM products
) ranked_products
WHERE rank_in_category = 1; -- Берём только первые места в каждой категории
2. Выборка всех записей, попадающих в топ по пороговому значению Например, найти все товары, чья цена входит в топ-10% самых дорогих.
-- Определяем пороговое значение (цену, выше которой находятся топ-10% товаров)
SET @threshold = (
SELECT MIN(price) FROM (
SELECT price FROM products ORDER BY price DESC LIMIT (
SELECT CEIL(COUNT(*) * 0.1) FROM products -- 10% от общего количества
)
) top_prices
);
-- Выбираем все товары, цена которых >= этому порогу
SELECT * FROM products WHERE price >= @threshold ORDER BY price DESC;
3. Топ с учётом одинаковых значений (с использованием DENSE_RANK)
Если несколько товаров имеют одинаковую цену и должны занимать одно место в рейтинге.
SELECT
id, name, price,
DENSE_RANK() OVER (ORDER BY price DESC) as price_rank
FROM products
ORDER BY price_rank
LIMIT 10;
В контексте PHP и фреймворков:
// Laravel Eloquent
$topProducts = Product::orderBy('price', 'desc')->take(5)->get();
// Doctrine (Symfony)
$topProducts = $entityManager->createQuery(
'SELECT p FROM AppEntityProduct p ORDER BY p.price DESC'
)->setMaxResults(5)->getResult();
Ключевой момент: LIMIT без ORDER BY даёт недетерминированный результат, так как порядок записей без явной сортировки не гарантирован. Всегда используйте ORDER BY для задач, связанных с "топом".