Выберите самую последнюю строку с GROUP BY в MySQL - PullRequest
18 голосов
/ 16 апреля 2011

Я пытаюсь выбрать каждого пользователя с последним платежом.У меня сейчас запрос выбирает первый платеж пользователей.Т.е. если пользователь сделал два платежа, а payment.id s - 10 и 11, запрос выбирает пользователя с информацией для идентификатора платежа 10, а не 11.

  SELECT users.*, payments.method, payments.id AS payment_id 
    FROM `users` 
         LEFT JOIN `payments` ON users.id = payments.user_id 
GROUP BY users.id

Я добавил ORDER BY payments.id, но запрос, кажется, игнорирует его и по-прежнему выбирает первый платеж.

Вся помощь приветствуется.Спасибо.

Ответы [ 6 ]

19 голосов
/ 25 апреля 2013

Вы хотите групповой максимум ; по сути, сгруппируйте таблицу платежей, чтобы определить максимальные записи, затем объедините результат с самим собой, чтобы получить другие столбцы:

SELECT users.*, payments.method, payments.id AS payment_id
FROM   payments NATURAL JOIN (
  SELECT   user_id, MAX(id) AS id 
  FROM     payments
  GROUP BY user_id
) t RIGHT JOIN users ON users.id = t.user_id

Обратите внимание, что MAX(id) может не быть " самым последним платежом ", в зависимости от вашего приложения и схемы: обычно лучше определить " самый последний " на основе TIMESTAMP чем основано на синтетических идентификаторах, таких как AUTO_INCREMENT столбец первичного ключа.

2 голосов
/ 24 августа 2017

Я давно читал следующее решение на SO, но не могу найти ссылку на кредит, но здесь идет речь:

SELECT users.*, payments.method, payments.id AS payment_id, payments2.id
FROM users
JOIN payments
    ON users.id = payments.user_id 
LEFT JOIN payments2
    ON payments.user_id = payments2.user_id
    AND payments.id < payments2.id
WHERE payments2.id IS NULL

Чтобы понять, как это работает, просто отбросьте WHERE payments2.id IS NULL ивы увидите, что происходит, например, это может привести к следующему выводу (я не создал схему, чтобы проверить это, так что это псевдо-вывод).Предположим, что в payments есть следующие записи:

id | user_id | method
1  | 1       | VISA
2  | 1       | VISA
3  | 1       | VISA
4  | 1       | VISA

И приведенный выше SQL (без предложения WHERE payments2.id IS NULL) должен выдать:

users.id | payments.method | payments.id | payments2.id
1        | VISA            | 1           | 2
1        | VISA            | 1           | 3
1        | VISA            | 1           | 4
1        | VISA            | 2           | 3
1        | VISA            | 2           | 4
1        | VISA            | 3           | 4
1        | VISA            | 4           | NULL

Как вы можете видетьпоследняя строка дает желаемый результат, и поскольку payments2.id > 4 нет, LEFT JOIN приводит к payments2.id = NULL.

Я обнаружил, что это решение намного быстрее (из моих ранних тестов), чем принятоеответ.

Использование другой схемы, но аналогичного запроса, из 16095 записей:

select as1.*, as2.id
from allocation_status as1
left join allocation_status as2 
    on as1.allocation_id = as2.allocation_id
    and as1.id < as2.id
where as2.id is null;

16095 rows affected, taking 4.1ms

По сравнению с принятым ответом MAX / подзапрос:

SELECT as1.* 
FROM allocation_status as1
JOIN (
    SELECT max(id) as id
    FROM allocation_status
    group by allocation_id
) as_max on as1.id = as_max.id 

16095 rows affected, taking 14.8ms
2 голосов
/ 10 ноября 2014

Я только что столкнулся с почти такой же проблемой и нашел эти ответы полезными.Похоже, мое тестирование показало, что вы можете сделать его несколько проще, чем принятый ответ, а именно:60 000 платежей, и запрос выполняется за 0,024 секунды.

1 голос
/ 26 июня 2014

Мое решение:

SELECT

u.codigo, 
u.nome,  
max(r.latitude),  
max(r.longitude),  
max(r.data_criacao) 

from TAB_REGISTRO_COORDENADAS  r

inner join TAB_USUARIO u

on u.codigo = r.cd_usuario

group by u.codigo
0 голосов
/ 24 июля 2012

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

    SELECT  u.*, p.method, p.id AS payment_id
    FROM    (
        SELECT  DISTINCT users.id
        FROM    users
        ) ur
    JOIN    payments p
    ON      p.id =
        (
        SELECT  pt.id
        FROM    payments pt
        WHERE   pt.user_id = ur.id
        ORDER BY
                pt.id DESC
        LIMIT 1
        )
0 голосов
/ 18 мая 2011

Сделав еще один шаг вперед, мы также можем использовать:

select payment_id, cust_id, amount, payment_method 
from my_table where payment_id in 
(
    select max(payment_id) from my_table group by cust_id
);

... но этот запрос также занимает слишком много времени в моем контексте.Внутренний избранник курит быстро, но внешний занимает некоторое время, и только 124 результата из внутреннего.Идеи?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...