2012-04-17 4 views
7

У меня есть две таблицы: tableA (idA, titleA) и tableB (idB, idA, textB) с отношением друг к другу. Для каждой строки в таблице A я хочу получить последние 5 строк, соответствующих таблице B (упорядочен по idB).Получить первые/последние n записей в группе по

Я попытался

SELECT * FROM tableA INNER JOIN tableB ON tableA.idA = tableB.idA LIMIT 5 

, но это просто ограничение глобального результата INNER JOIN, тогда как я хочу, чтобы ограничить результат для каждого из различных tableA.id

Как я могу это сделать?

Благодаря

+0

За последние 5 дней ... Есть ли основа для последних 5 в таблице B или только последние 5 на основе «idB», которая будет казаться столбцом последовательности с автоматическим увеличением. Если на основе даты, какой столбец будет ... – DRapp

+0

Он основан на idB, который автоматически увеличивается. –

+0

Похожие вопросы: http://stackoverflow.com/questions/4688664/mysql-select-n-records-base-on-group-by и http://stackoverflow.com/questions/5319643/top-n-per- group-with-multiple-table-joins и, возможно, http://stackoverflow.com/q/7539548 - расширение [this] (http://stackoverflow.com/q/8748986) и [это] (http://stackoverflow.com/q/1313120) – TMS

ответ

2

Я думаю, что это то, что вам нужно:

SELECT tableA.idA, tableA.titleA, temp.idB, temp.textB 
FROM tableA 
INNER JOIN 
(
    SELECT tB1.idB, tB2.idA, 
    (
     SELECT textB 
     FROM tableB 
     WHERE tableB.idB = tB1.idB 
    ) as textB 
    FROM tableB as tB1 
     JOIN tableB as tB2 
      ON tB1.idA = tB2.idA AND tB1.idB >= tB2.idB 
    GROUP BY tB1.idA, tB1.idB 
    HAVING COUNT(*) <= 5 
    ORDER BY idA, idB 
) as temp 
ON tableA.idA = temp.idA 

Более подробную информацию об этом методе здесь:

http://www.sql-ex.ru/help/select16.php

+1

Почему у вас есть третий вложенный выбор ('select textB из tableB, где tableB.idB = tB1.idB')? Этот подзапрос можно заменить только на 'tB1.textB'! – TMS

+0

и замените 'inner join' на' join'.Не делайте его более загадочным, чем это :-) – TMS

+2

@ user1336526, я упростил и исправил это решение Карлоса, см. Мой ответ. – TMS

0

Убедитесь, что ваш «B» таблица имеет индекс (IDA, IDB) для оптимизации порядка по целям, так для каждого «А» ID, он может быстро иметь «В» убывающем порядке, таким образом, поставив новейший к началу PER EACH «A» ID. Используя переменные MySQL, каждый раз, когда изменяется идентификатор «А», он сбрасывает ранг обратно на 1 для следующего «А».

select 
     B.idA, 
     B.idB, 
     B.textB 
     @RankSeq := if(@LastAGroup = B.idA, @RankSeq +1, 1) ARankSeq, 
     @LastAGroup := B.idA as ignoreIt 
    from 
     tableB B 
     JOIN tableA A 
      on B.idA = A.idA, 
     (select @RankSeq := 0, @LastAGroup := 0) SQLVars 
    having 
     ARankSeq <= 5 
    order by 
     B.idA, 
     B.idB DESC 
+0

Ух! Неприятный запрос :-) Посмотрите на [гораздо более простой вариант] (http://stackoverflow.com/a/4688699/684229). Во всяком случае, в производительности есть большой недостаток - MySQL должен пройти через все строки. – TMS

0
select * from tablea ta, tableb tb 
where ta.ida=tb.idb and tb.idb in 
(select top 5 idb from tableB order by idb asc/desc) 
  • (по возрастанию, если вы хотите более низкие IdS desc, если вы хотите более высокие идентификаторы)
  • менее сложная и легко включать несколько условий
  • если верхний пункт нет в использовании MySQL предельного пункта (я не имею много знаний Abt MySQL)
+0

Он запрашивает верхние 5 в таблицеB для каждой строки в таблице A. Это просто ограничивает таблицу B верхними 5 строками, упорядоченными по idb. Также вам нужно использовать LIMIT для MySQL, а не TOP. – Aaron

+0

благодарю вас за ваши комментарии, я понимаю свою ошибку ...... будет ли это работать .... выберите * from tablea ta, tableb tb, где ta.ida = tb.idb и tb.idb in (выберите idb из tableB, tableA tableB.idb = tableA.ida order by idb asc/desc limit 5) .. –

5

намного упрощено и исправленное решение Карлоса (его решение будет возвращать первые 5 строк, не последний ...):

SELECT tB1.idA, tB1.idB, tB1.textB 
FROM tableB as tB1 
    JOIN tableB as tB2 
     ON tB1.idA = tB2.idA AND tB1.idB <= tB2.idB 
GROUP BY tB1.idA, tB1.idB 
HAVING COUNT(*) <= 5 

в MySQL вы можете использовать tB1.textB даже если группа по запросу, потому что вы группировать по IDB в первой таблице, так что только одно значение tB1.textB для каждого group ...

+0

Просто заметьте, просто не забывайте: все еще вопрос, какое решение будет лучше соответствовать - решение соединения в принципе квадратично, а ранга является линейным. Тем не менее, вполне вероятно, что оптимизатор SQL превратит квадратичную задачу в линейную, в то время как от решения ранжирования не ожидается никаких оптимизаций. То же самое относится к решениям [этого похожего вопроса] (http://stackoverflow.com/q/8748986). – TMS

+0

Мой общий опыт работы с MySQL заключается в том, что если вы можете переписать запрос подзапроса/ранжирования для объединения, это будет быстрее .. – TMS

Смежные вопросы