Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SQL (от Сани Сафронова).doc
Скачиваний:
71
Добавлен:
03.06.2015
Размер:
969.22 Кб
Скачать

Как вывести по n строк из каждой группы?

    Моисеенко С.И. (23-05-2009)

Такой вопрос возникает, например, когда на сайте требуется вывести по 3 самых свежих анонса в каждой новостной группе, или рекламу 5 самых популярных товаров в каждой категории.

Чтобы решить эту задачу, нужно выполнить разбиение всего набора строк на группы, произвести сортировку по требуемому критерию (по дате или количеству продаж) в пределах каждой группы и последовательно выбрать требуемое количество строк, начиная с первой строки в каждой группе.

Подобную задачу можно решать процедурно, используя временные таблицы и/или курсоры. Здесь же я хочу предложить два решения в стиле тех задач, которые мы решаем на сайте, т.е. одним запросом SELECT. Первое решение - "классическое", которое должно работать на большинстве СУБД; второе решение использует новые конструкции, которые появились в стандарте SQL:1999 и поддерживаются еще не так широко.

Рассмотрим следующую задачу:

Вывести из таблицы Product по три модели с наименьшими номерами из каждой группы, характеризуемой типом продукции.

Т.е. требует получить 3 компьютера, 3 ноутбука и 3 принтера, номера которых меньше номеров остальных моделей в своей группе. Поскольку номер модели является уникальным в таблице Product, то тут не возникает проблем с дубликатами. Заметим, что проблема дубликатов не является принципиальной, однако потребует уточнения формулировки.

"Классическое" решение

Это решение опирается на алгоритм нумерации строк, возвращаемых запросом. Т.е. мы нумеруем строки, а потом выбираем те их них, которые имеют номера, меньшие заданного числа. Следуя упомянутому алгоритму, запрос, который нумерует упорядоченный по возрастанию номера модели весь набор строк в таблице, можно записать так:

SELECT Pr1.model, COUNT(*) num

FROM Product Pr1 JOIN Product Pr2

ON Pr1.model >= Pr2.model

GROUP BY Pr1.model

Только для решения нашей задачи нужно пронумеровать не весь набор, а каждую группу в отдельности. Этого легко добиться, если в условие соединения таблиц добавить условие совпадения типов продукции, а также добавить группировку по типу:

SELECT Pr1.model, Pr1.type, COUNT(*) num

FROM Product Pr1 JOIN Product Pr2

ON Pr1.type = Pr2.type AND Pr1.model >= Pr2.model

GROUP BY Pr1.type, Pr1.model

HAVING COUNT (*) <= 3

ORDER BY type, model

Предложение

HAVING COUNT (*) < = 3

в соответствии с условием задачи ограничивает тремя количество строк в каждой группе. Фактически мы уже решили задачу. Осталось лишь добавить производителя (maker), что также можно сделать разными способами. Например, еще раз соединить по номеру модели приведенный выше запрос с таблицей Product, или использовать коррелирующий подзапрос в предложении SELECT. В учебных целях приведу оба подхода.

1. Соединение

SELECT maker, X.model, X.type

FROM product JOIN (

SELECT Pr1.model, Pr1.type

FROM Product Pr1 JOIN Product Pr2

ON Pr1.type = Pr2.type AND Pr1.model >= Pr2.model

GROUP BY Pr1.type, Pr1.model

HAVING COUNT (*) <= 3

) X on X.model = product.model

ORDER BY type,model

Здесь мы исключили лишний столбец num, который использовался в демонстрационных целях, поскольку нам не требуется выводить номер строки.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]