在MySQL中选择GROUP BY的最新行

Rya*_*yan 19 mysql sql group-by

我正在尝试选择最近付款的每个用户.我现在的查询选择了用户的第一笔付款.即,如果用户进行了两次付款并且payment.ids为10和11,则查询选择具有付款ID 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
Run Code Online (Sandbox Code Playgroud)

我添加了ORDER BY payments.id,但查询似乎忽略它,仍然选择第一笔付款.

所有帮助赞赏.谢谢.

egg*_*yal 20

你想要groupwise最大值 ; 本质上,将支付表分组以识别最大记录,然后将结果与自身连接以获取其他列:

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
Run Code Online (Sandbox Code Playgroud)

请注意,这MAX(id)可能不是" 最近的付款 ",具体取决于您的应用程序和架构:通常最好确定基于合成标识符(例如主键列)的" 最新 " .TIMESTAMPAUTO_INCREMENT


Ric*_*ing 5

我刚刚处理了几乎完全相同的问题,发现这些答案很有帮助。我的测试似乎表明您可以使其比接受的答案稍微简单一些,即:

SELECT u.*, p.method, p.id AS payment_id 
FROM `users` u, `payments` p
WHERE u.id = p.user_id 
    AND p.id = (SELECT MAX(p2.id) FROM payments p2
                    WHERE p2.user_id = u.id);
Run Code Online (Sandbox Code Playgroud)

我没有对差异进行性能测试,但我正在处理的数据库有超过 50,000 个用户和超过 60,000 笔付款,查询运行时间为 0.024 秒。


Dan*_*anH 5

很久以前我阅读了以下解决方案,但我找不到信用链接,但这里是:

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
Run Code Online (Sandbox Code Playgroud)

要了解它是如何工作的,只需删除它WHERE payments2.id IS NULL,您就会看到发生了什么,例如它可以产生以下输出(我没有构建模式来测试它,所以它是伪输出)。假设有以下记录payments

id | user_id | method
1  | 1       | VISA
2  | 1       | VISA
3  | 1       | VISA
4  | 1       | VISA
Run Code Online (Sandbox Code Playgroud)

上面的 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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,最后一行产生了所需的结果,由于没有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
Run Code Online (Sandbox Code Playgroud)

与 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
Run Code Online (Sandbox Code Playgroud)