You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

求MySQL 5.7替代MariaDB 10.4分区取最新记录的SQL方案

解决MySQL 5.7无法使用ROW_NUMBER() OVER(PARTITION BY)的替代方案

嘿,这个兼容性问题我之前也碰到过——MySQL 5.7确实没支持窗口函数(ROW_NUMBER()、PARTITION BY这些都是MySQL 8.0才加进去的),而MariaDB 10.2+就已经支持了,所以会出现你说的运行不了的情况。下面给你几个实用的替代方案,都能实现“获取每个A_id对应的最新B记录”的需求:

方案一:关联子查询(最直观易读)

这个方法逻辑很清晰,先通过子查询找出每个a.id对应的最大Created_at,再关联回原表拿到完整记录,适合数据量不是特别大的场景:

SELECT a.id AS A_id, b.id AS B_id, b.Created_at
FROM alpha a
JOIN beta b ON b.a_id = a.id
WHERE b.Created_at = (
    SELECT MAX(Created_at)
    FROM beta
    WHERE a_id = a.id
);

⚠️ 注意:如果同一个a.id下有多个记录的Created_at完全相同,这个查询会返回所有这些记录。如果你的业务里Created_at是唯一的,或者允许返回同时间的多条记录,这个方案最省心。

方案二:GROUP BY + 关联(确保唯一结果)

如果需要保证每个A_id只返回一条记录(哪怕有相同的Created_at),可以先按a.id分组拿到最大Created_at,再结合b.id的最大值(或其他业务规则)来筛选唯一记录:

SELECT a.id AS A_id, b.id AS B_id, b.Created_at
FROM alpha a
JOIN (
    SELECT a_id, MAX(Created_at) AS max_created, MAX(id) AS max_b_id
    FROM beta
    GROUP BY a_id
) b_max ON a.id = b_max.a_id
JOIN beta b ON b.a_id = b_max.a_id AND b.Created_at = b_max.max_created AND b.id = b_max.max_b_id;

这里用MAX(id)来在Created_at相同时选id最大的那条,你也可以根据自己的业务需求换成其他聚合规则,比如MIN(id)。

方案三:用户变量模拟窗口函数(大数据量友好)

如果你的数据量很大,子查询可能性能跟不上,可以用MySQL的用户变量来模拟ROW_NUMBER()的分区排序效果:

SELECT A_id, B_id, Created_at
FROM (
    SELECT 
        a.id AS A_id, 
        b.id AS B_id, 
        b.Created_at,
        @rn := CASE 
            WHEN @current_a_id = a.id THEN @rn + 1 
            ELSE 1 
        END AS rn,
        @current_a_id := a.id
    FROM alpha a
    JOIN beta b ON b.a_id = a.id
    CROSS JOIN (SELECT @current_a_id := NULL, @rn := 0) vars
    ORDER BY a.id, b.Created_at DESC
) q
WHERE rn = 1;

⚠️ 注意:这个方法依赖于ORDER BY的执行顺序,在MySQL 5.7中是稳定的,但一定要确保排序规则正确,不然可能会出现不符合预期的结果。

你可以根据自己的数据规模、业务规则来选最合适的方案,测试下哪种在你的环境里性能最好~

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

火山引擎 最新活动