Ищите способ ограничить результаты SQL 3 результатами для определенного столбца - PullRequest
2 голосов
/ 22 февраля 2010

У меня есть список из 9 идентификаторов пользователей, и я хочу выбрать 3 записи для каждого идентификатора пользователя.

Мой текущий запрос выглядит следующим образом.

SELECT * FROM entries WHERE user_id IN (1,2,3,4,5,6,7,8,9) LIMIT 27

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

Я попытался создать UNION из 9 отдельных запросов, каждый из которых имеет свой собственный предел 3, но на сервере это происходит очень медленно.

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

Ответы [ 4 ]

2 голосов
/ 23 февраля 2010

Если предположить, что таблица entries имеет еще один столбец id в качестве уникального идентификатора, следующий запрос должен работать (не проверено):

SELECT      e.*
FROM        entries e
INNER JOIN (SELECT      e.id
            FROM        entries e
            INNER JOIN  entries x
                    ON  e.user_id = x.user_id
                    --// define the field (ID, TimeStamp) here to specify which top 3, 
                    --// and use sign to specify ASC/DESC (<=, >=)
                    AND e.id <= x.id 
            GROUP BY    e.id
            HAVING      COUNT(*) <= 3 --//only top 3
            ) f
        ON  e.id = f.id

Используя этот запрос, вы также можете определить, какие 3 строки вы хотели бы видеть (упорядочить по ID / TimeStamp, ASC или DESC) Если в таблице entries есть только несколько столбцов, вы можете GROUP BY всех столбцов таблицы и избежать sub-select.

0 голосов
/ 24 февраля 2010

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

EG.

create temporary table temptab ( userid int not null, 
                                 rank int auto_increment not null,
                                 primary key (userid, rank ) );

insert into temptab select userid, NULL from entries order by userid;  

# change the "order by" to fit your criteria - eg. order by last_used desc, ...

delete from temptab where rank > 3;
select * from temptab order by userid, rank;

должен вернуть:

   1, 1
   1, 2
   1, 3
   2, 1
   ...

Для этого потребуется настройка в соответствии с вашими потребностями. Вероятно, также вставьте первичный ключ из таблицы записей во временную таблицу, чтобы соединение из temptab с записями могло дать некоторые полезные данные.

0 голосов
/ 23 февраля 2010

Попробуйте следующее

SELECT TOP 3 * FROM entries
WHERE user_id = 1

UNION ALL


SELECT TOP 3 * FROM entries
WHERE user_id = 2

UNION ALL

...
0 голосов
/ 22 февраля 2010

Если вы просто выбираете 3 случайные записи, то, вероятно, лучше использовать UNION.

Мне трудно поверить, что простой UNION "очень медленный на сервере", если у вас нет плохо проиндексированной таблицы или вы не выбираете несколько огромных столбцов. Вам действительно нужно SELECT *? Вероятно, нет.

Пожалуйста, обновите ваш вопрос с SHOW CREATE TABLE entries\G, а также выводом EXPLAIN SELECT ... UNION ... \G

...