You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过SQL批量获取指定用户符合条件的最新支付记录?

批量获取用户最新支付记录的SQL问题

我需要批量获取一组用户ID的最新支付记录,但一直无法通过统一查询实现。

最初使用的SQL查询:

SELECT t1.*
FROM movements t1 LEFT JOIN movements t2
ON (t1.user = t2.user AND t1.id < t2.id)
WHERE t2.id IS NULL
AND t1.user IN ({$ids}) AND t1.type='payment' AND t1.concept!='4' AND t1.confirmed

该查询有一定效果,但部分记录被遗漏。调整条件为:

ON (t1.user = t2.user AND t1.id < t2.id)
WHERE t2.id IS NULL AND t2.date IS NULL

结果有所增加,但仍有部分记录未被选中。以下是两个查询无结果的示例数据:

id      user    concept             date                    type        confirmed
---------------------------------------------------------------------------------
29755   107     3                   2022-06-12 00:01:00     payment     1
31257   107     3                   2022-07-12 00:00:00     payment     1
32189   107     3                   2022-08-12 00:00:00     payment     1         
32460   107     COMISSION BALANCE   2022-08-23 10:50:50     comission   
id      user    concept             date                    type        confirmed
---------------------------------------------------------------------------------
27298   8408    3                   2022-03-11 08:44:53 40  payment     
28446   8408    3                   2022-03-11 00:01:00 40  payment     1         
28447   8408    3                   2022-04-19 17:22:42 40  payment

而针对单个用户的查询能得到正确结果:

SELECT * FROM movements WHERE user=107 AND type='payment' AND concept!='4' AND confirmed ORDER BY id DESC LIMIT 1

返回结果:

id      user    concept             date                    type        confirmed
---------------------------------------------------------------------------------
32189   107     3                   2022-08-12 00:00:00     payment     1

我可以通过foreach循环对每个用户单独调用查询,但希望避免这种方式。问题出在“最顶部”的行不符合完整条件,但不知道如何让SQL筛选出符合要求的记录,请问如何简洁实现这一需求?


解决方案

原查询问题分析

你原来的左连接方法失效的原因是:当用户存在非支付类型的更大ID记录时(比如第一个示例里的comission类型记录),t2会匹配到这条记录,导致t2.id不为空,从而过滤掉了用户最新的支付记录。原查询没有限定t2的记录类型,错误地把所有更大ID的记录都纳入了判断范围。

方法1:使用窗口函数(推荐)

利用ROW_NUMBER()窗口函数按用户分组,对符合条件的支付记录按ID降序排序,取每组的第一条记录:

SELECT *
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (PARTITION BY user ORDER BY id DESC) AS rn
    FROM movements
    WHERE 
        user IN ({$ids}) 
        AND type = 'payment' 
        AND concept != '4' 
        AND confirmed = 1
) t
WHERE rn = 1;
  • 内层查询先筛选出所有符合条件的支付记录;
  • PARTITION BY user按用户分组,ORDER BY id DESC确保每组内最新的记录排在最前面;
  • 外层查询取rn=1的记录,即每个用户最新的支付记录。

方法2:子查询获取每个用户的最大符合条件ID

先统计每个用户符合条件的最大支付记录ID,再关联原表获取完整数据:

SELECT m.*
FROM movements m
JOIN (
    SELECT user, MAX(id) AS max_id
    FROM movements
    WHERE 
        user IN ({$ids}) 
        AND type = 'payment' 
        AND concept != '4' 
        AND confirmed = 1
    GROUP BY user
) t ON m.user = t.user AND m.id = t.max_id;
  • 子查询先找出每个用户符合条件的支付记录中的最大ID;
  • 主查询通过用户ID和最大ID关联,获取对应的完整记录。

这两种方法都能高效批量获取目标数据,避免循环查询的性能问题。


内容的提问来源于stack exchange,提问作者karmaral

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:45:35