Получение последних n записей для каждой группы

Допустим, у меня есть следующая таблица:

id  coulmn_id  value    date
1      10      'a'     2016-04-01
1      11      'b'     2015-10-02
1      12      'a'     2016-07-03
1      13      'a'     2015-11-11
2      11      'c'     2016-01-10
2      23      'd'     2016-01-11
3      11      'c'     2016-01-09
3      111     'd'     2016-01-11
3      222      'c'     2016-01-10
3      333      'd'     2016-01-11

для n = 3, я хочу получить последние n записей <= 3 для каждого идентификатора. Итак, у меня будет следующий вывод:

id  column_id  value    date
1      10        'a'     2016-04-01
1      12        'a'     2016-07-03
1      13        'a'     2015-11-11
2      11        'c'     2016-01-10
2      23        'd'     2016-01-11
3      111       'd'     2016-01-11
3      222       'c'     2016-01-10
3      333       'd'     2016-01-11

Ответ 1

Я отвечаю, потому что упомянутый вопрос имеет нестабильный ответ (я прокомментирую это там).

Вот решение, которое должно работать:

select t.*
from (select t.*,
             (@rn := if(@id = id, @rn + 1,
                        if(@id := id, 1, 1)
                       )
             ) as seqnum
      from t cross join
           (select @rn := 0, @id := -1) params
      order by id, date desc
     ) t
where seqnum <= 3;

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

Ответ 2

Вы можете сделать это с использованием переменных. Сначала выполните результаты в обратном порядке и назначьте номер строки, затем отфильтруйте результаты для чисел строк, меньших или равных 3, и измените порядок:

select   id, value, date
from     (
           select      id, value, date,
                       @rn := if(@id = id, @rn+1, if (@id := id, 1, 1)) rn
           from        mytable,
           cross join  (@id := null, @rn := null) init
           order by    id, date desc
         ) as base
where    rn <= 3
order by id, date asc