2015-11-01 3 views
1

Моя цель - захватить последние несколько строк (я пытаюсь три) из таблицы для каждой учетной записи. У меня нет проблем с получением первых строк, но у меня возникли проблемы с составлением первых трех последних строк. Например, предположим, что у меня есть следующая таблица:Как захватить последние три строки в MySQL

+--------+------------+------------+-----------+ 
| rownum | entryDate | particular | accountID | 
+--------+------------+------------+-----------+ 
|  1 | 2015-10-01 | Item1  |   1 | 
|  2 | 2015-10-01 | Item2  |   1 | 
|  3 | 2015-10-02 | Item3  |   1 | 
|  4 | 2015-10-02 | Item4  |   1 | 
|  5 | 2015-10-02 | Item5  |   2 | 
|  6 | 2015-10-03 | Item6  |   2 | 
|  7 | 2015-10-05 | Item7  |   3 | 
+--------+------------+------------+-----------+ 

То, что я пытаюсь получить это:

+--------+------------+------------+-----------+ 
| rownum | entryDate | particular | accountID | 
+--------+------------+------------+-----------+ 
|  4 | 2015-10-02 | Item4  |   1 | 
|  3 | 2015-10-02 | Item3  |   1 | 
|  2 | 2015-10-01 | Item2  |   1 | 
|  6 | 2015-10-03 | Item6  |   2 | 
|  5 | 2015-10-02 | Item5  |   2 | 
|  7 | 2015-10-05 | Item7  |   3 | 
+--------+------------+------------+-----------+ 

Где Item1 был удален, потому что он уже 3 перед ним. Я пробовал следующий код, но он не извлекает самые последние

select rownum, entryDate, particular, accountID 
from (
    select entryDate, particular, accountID 
    @rownum := if(@account = accountID, @rownum + 1, 1) rownum, 
    @account := accountID 
    from entries 
    join (select @rownum := 0, @account := 0) init 
    order by accountID, entryDate desc) t 
where t.rownum <= 3 -- Limits the rows per account 

Если кто-то может мне точку в правильном направлении, что было бы здорово!

EDIT: Однако то, что я извлечения в качестве результата:

+--------+------------+------------+-----------+ 
| rownum | entryDate | particular | accountID | 
+--------+------------+------------+-----------+ 
|  3 | 2015-10-02 | Item3  |   1 | 
|  2 | 2015-10-01 | Item2  |   1 | 
|  1 | 2015-10-01 | Item1  |   1 | 
|  6 | 2015-10-03 | Item6  |   2 | 
|  5 | 2015-10-02 | Item5  |   2 | 
|  7 | 2015-10-05 | Item7  |   3 | 
+--------+------------+------------+-----------+ 

Кроме того, если это поможет, я проверил это на MySQL Workbench, SQLbuddy, PHP (веб-приложения) и PHPMyAdmin, и все они производят одинаковый результат.

+0

Почему существует запрос подбора? в чем его цель? –

+0

Какой подзаголовок? Если вы имеете в виду тот, что находится внутри 'from', то это значит, что количество строк на одну учетную запись может быть ограничено до 3 на учетную запись. Подзапрос внутри соединения используется для инициализации переменных. – Jujunol

+1

Ваш запрос действительно дает именно тот результат, который вы указали - в чем проблема? – amdixon

ответ

1

Your query works for me если я исправлю ошибку синтаксиса.

select rownum, entryDate, particular, accountID 
from (
    select entryDate, particular, accountID, 
    @rownum := if(@account = accountID, @rownum + 1, 1) rownum, 
    @account := accountID 
    from entries 
    join (select @rownum := 0, @account := 0) init 
    ORDER BY accountid, entryDate desc 
) t 
where t.rownum <= 3; 

rownum entryDate   particular   accountID 
1  October, 02 2015  Item3    1 
2  October, 02 2015  Item4    1 
3  October, 01 2015  Item1    1 
1  October, 03 2015  Item6    2 
2  October, 02 2015  Item5    2 
1  October, 05 2015  Item7    3 

Обратите внимание, что Item1 и Item2 имеют одинаковый вход. Не предсказуемо, получите ли вы Item1, 3 и 4 или 2, 3 и 4. Однако вы никогда не должны получать Item1, 2 и 3.

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

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

@rownum := if(@account = accountID, @rownum + 1, 1) rownum, 
    @account := accountID 

Это трюк, который присваивает отдельный набор ролей для каждой учетной записи. Он полагается на то, что строки упорядочены по учетной записи и что @rownum устанавливается до @account.

Проблема в том, что я не думаю, что вы можете положиться на это.

+0

этот вариант поставлен отличается от того, что ему нужно ... 'Item1' не должен быть там, а' item2' должен быть там. Правильно? –

+0

Правильно, я не обратил внимания на то, что элементы 1 и 2 имели ту же дату в тестовых данных. Я заметил, что даже когда дата Date2 переключилась на * -02 в предоставленном ранее SQLFiddle, результат работает, это означает, что он имеет отношение к моему серверу. Я думаю:/ – Jujunol

+0

@Jujunol Я подозреваю, что проблема заключается в порядке операций для столбцов SELECT не является надежным. Я не совсем уверен. – Schwern

2

Безопасный способ написать этот запрос является:

select rownum, entryDate, particular, accountID 
from (select entryDate, particular, accountID, 
      (@rownum := if(@account = accountID, @rownum + 1, 
          if(@account := accountID, 1, 1) 
          ) 
      ) as rownum, 
     from entries cross join 
      (select @rownum := 0, @account := 0) init 
     order by accountid, entryDate desc 
    ) t 
where t.rownum <= 3; 

Это объясняется в documentation:

Как правило, кроме как в отчетности SET, вы никогда не должны назначить значение переменной пользователя и прочитать значение в том же . , , В следующем заявлении, вы можете подумать, что MySQL будет оценивать @a первый, а затем сделать задание второй:

SELECT @a, @a:[email protected]+1, ...; 

Однако, порядок вычисления выражений, включающих пользовательские переменные не определено.

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