Как сделать LIMIT по нескольким группам?

Avenus

Under Glory Yield
Как сделать LIMIT по нескольким группам?

Привет, всем! :)

В таблице есть записи, которые нужно вывести по группам g в N строк.

К примеру, запрос:
PHP:
SELECT id FROM t ORDER BY g LIMIT N
Понятен: получу N строк и сверху будут строки с минимальным значением g, снизу - с максимальным.

При этом, если строк с g=0 будет больше N, то получу строки только с g=0.
А с другими значениями g не получу.

Возможно ли сделать LIMIT в N строк для каждой группы значений g, т.е.,
к примеру, чтобы получить по N строк со значениями g равными 0, 1, 2 ... X?

-~{}~ 20.12.09 14:53:

P.S. Понимаю, что можно сделать несколько запросов для каждой группы с LIMIT N, но может быть есть более лучшее решение?
 

Adelf

Administrator
Команда форума
Avenus
У тебя действительно такая задача или ты другую задачу через задницу так делаешь? :)

>> prolis, что это значит?
Это значит, что он хотел что-то сказать, но передумал.
 

Avenus

Under Glory Yield
Adelf, всё возможно, но встал перед фактом.

Есть строки в одной таблице с g=0 и g=1.
g=0 с ID: 1..9
g=1 с ID: 10..19

Нужно показать по 5 строк из каждой группы.

Сортировка в запросе по сложным критериям. Может быть стоит запрос привести реальный?

-~{}~ 21.12.09 17:04:

Это значит, что он хотел что-то сказать, но передумал.
Мог бы ничего не писать. Зачем писать точку? :)
 

Adelf

Administrator
Команда форума
Ну тут от задачи зависит.
Возможно правильно будет ввести поле-флаг для данного запроса и одним запросом все забирать. Если получится хорошо организовать обновление данного поля, то хороший вариант.
Ну либо забить и делать несколько запросов.

Повторюсь - зависит от задачи.
 

Avenus

Under Glory Yield
Adelf, поверь, задача не "через жопу" :)
Ты имеешь ввиду под этим:
Возможно правильно будет ввести поле-флаг для данного запроса и одним запросом все забирать. Если получится хорошо организовать обновление данного поля, то хороший вариант.
Сделать запрос, который будет выбирать только поля с установленным флагом для обоих групп на 5 строк?
Возможно, что это решение. Осталось только подумать, как организовать обновление.

Потому как несколько запросов я могу сделать без проблем, что и сделал на данный момент.
 

Adelf

Administrator
Команда форума
Ну согласись, что описал ты задача чуть более чем никак.

Вот у тебя есть поле g.
Делаем поле IsFirstGroup.
Можно например после каждого insert или update или delete(т.е. любого DML-запроса) запускать скрипт, который каждой записи из первых пятерок по каждому значению g в поле IsFirstGroup запишет 1. А у других записей будет ноль.
Следовательно запрос вытаскивающий нужные данные будет такой:
select ..... where IsFirstGroup = 1 order by ...

Если таблица обновляется редко и если выбирается всегда только 5 первых, то это вполне можно организовать. Если выбирается не только 5, но и больше, то можно более общее решение.
Поле IsFirstGroup переименовать в OrderIndex и писать туда порядковый номер записи в ДАННОМ значении g.
Т.е. для твоего примера будет так:
ID g OrderIndex
1 1 1
2 1 2
3 1 3
........
9 1 9
10 2 1
11 2 2
12 2 3
....
А запрос будет таким:
select ..... where OrderIndex <= 5 order by ...
 

Avenus

Under Glory Yield
Adelf, решение хоть и предложил, но только для ручного указания IsFirstGroup, что есть бред.
Автоматически сделать тоже самое, что указать IsFirstGroup=1 по-очереди каждой группе. Это "шило на мыло".

И, при переносе или удалении записи, у которой OrderIndex<=5 выборка уже неправильная. Делать снова несколько запросов, чтобы перестроить все совсем не подходит.

Поэтому твое высказывание:
Можно например после каждого insert или update или delete(т.е. любого DML-запроса) запускать скрипт, который каждой записи из первых пятерок по каждому значению g в поле IsFirstGroup запишет 1
И как же? :)
Это же то же самое, что и выбрать по 5 записей из каждой группы.

prolis, это решение не подходит, либо я не пойму как его применить
Т.к. дополнительное поле OrderIndex с auto_increment в составном primary_key будет постоянно увеличиваться.
Как потом выбрать по 5 записей в каждой группе?

-~{}~ 28.01.10 20:54:

Попробовал написать сначала выбор id строк, чтобы потом по
ним выбрать всю информацию.

Должно быть: из таблицы групп t2 выбираются все группы, потом по их id выбираются id записей по группам по 5 штук:
PHP:
SELECT g.*,(
SELECT GROUP_CONCAT(t1.id SEPARATOR ",")
FROM t1
WHERE t1.g=g.id
LIMIT 5
) as list_id FROM(
SELECT t2.id
FROM t2
) as g
Но, не хочет выбирать по 5 записей, выводит все. Почему?
 

Adelf

Administrator
Команда форума
опомнился через месяц :)


>> И как же?
>> Это же то же самое, что и выбрать по 5 записей из каждой группы.

Ну при удалении например записи - надо будет затронуть только ту группу в которой эта запись была. Понятно, что это шило на мыло, но все это только ради того, чтобы не делать кучу запросов при выборке каждый раз.
 

Avenus

Under Glory Yield
опомнился через месяц
Я не работаю, когда все отдыхают :)

Ну при удалении например...
Я согласен, что лучше занести и обновить ключи для быстрой выборки потом, но как выбрать те строки, которым указать нужные ключи?
 

Adelf

Administrator
Команда форума
У тебя проблема была только когда выбираешь много категорий. Для одной простой LIMIT 5 - и спокойно раздаешь рейтинги.
 

Avenus

Under Glory Yield
Так категорий много. Получается по-очереди к каждой категории сделать 2 запроса:
- всем у кого был 1 присвоить ключ=0
- на последние 5 присвоить ключ=1
...
А насчет group_concat что скажешь?
 

Adelf

Administrator
Команда форума
Ну при удалении например записи - надо будет затронуть только ту группу в которой эта запись была. Update затронет две группы возможно. Insert тоже одну. Ну а уж распределить вначале все категории которые есть - это можно уж.. один раз то.
 

Avenus

Under Glory Yield
Adelf, все равно не хочется этим заниматься. Проблемы лишние. Я выше написал запрос с group_concat.
Изучал доки, видимо не понял чего-то.

Так вот, запрос по идее должен выполнить то, что мне нужно без лишних заморочек.

-~{}~ 29.01.10 08:50:

Вот он, запрос, наконец-то:
PHP:
select t1.id
from tbl as t1
where 5>=(
 select count(*)+1
 from tbl as t2
 where t1.g=t2.g
)
order by t1.g
Получаю по 5 записей из каждой группы :)
 
Сверху