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

使用GROUP BY子查询关联表后出现重复行的原因排查

解决产品最新更新状态查询的重复行问题

问题背景

需要获取各产品ID的最新更新状态,现有Products和Transactions两张表。单独执行select ID, max(Last_Updated) from Transactions group by ID能得到正确的各产品最新时间行数,但关联Products表补充信息时,部分ID返回两行(通常是最近两次状态),而非预期的仅最新日期行。

执行的关联查询

select p.ID, p.Product, T.Last_Updated from Products P
inner join Transactions T on p.ID = T.ID
where p.ID in (1,2,3)
and T.Last_Updated in (select ID, max(Last_Updated) from Transactions group by ID)
order by p.ID desc

表结构

Products表

IDProduct
1Blueberry Muffin
2Chocolate Chip Cookie
3Apple

Transactions表

IDStatusLast_Updated
1purchased1/2/2023 11:16:05 am
1added-inventory1/2/2023 11:00:01 am
1displayed1/2/2023 11:05:22 am
1deleted-inventory1/2/2023 11:17:12 am
2etcetc
3etcetc

实际结果

IDProductStatusLast_Updated
1Blueberry Muffinpurchased1/2/2023 11:16:05 am
1Blueberry Muffindeleted-inventory1/2/2023 11:17:12 am
3Chocolate Chip Cookiedeleted-inventory1/2/2023 11:25:11 am
2Appledeleted-inventory1/2/2023 11:22:35 am

预期结果

IDProductStatusLast_Updated
1Blueberry Muffindeleted-inventory1/2/2023 11:17:12 am
3Chocolate Chip Cookiedeleted-inventory1/2/2023 11:25:11 am
2Appledeleted-inventory1/2/2023 11:22:35 am

问题原因

原查询的核心错误在于T.Last_Updated in (select ID, max(Last_Updated) from Transactions group by ID)这一条件:

  • 子查询返回了ID和max(Last_Updated)两列,但IN操作符仅能匹配单列值,数据库会忽略子查询的第一列(ID),仅用max(Last_Updated)的集合进行匹配。
  • 这导致只要某条交易的Last_Updated等于任意产品的最新更新时间,就会被筛选出来,而非仅匹配当前产品自身的最新时间。

解决方案

方案1:使用多列IN匹配(支持MySQL 8.0+、PostgreSQL等数据库)

直接让(T.ID, T.Last_Updated)匹配子查询返回的ID和对应最新时间的组合:

select p.ID, p.Product, T.Status, T.Last_Updated 
from Products P
inner join Transactions T on p.ID = T.ID
where p.ID in (1,2,3)
and (T.ID, T.Last_Updated) in (select ID, max(Last_Updated) from Transactions group by ID)
order by p.ID desc

方案2:先预查询最新时间再关联

先通过子查询获取每个ID的最新时间,再依次关联Products和Transactions表:

select p.ID, p.Product, T.Status, T.Last_Updated
from Products p
inner join (
    select ID, max(Last_Updated) as Last_Updated
    from Transactions
    group by ID
) latest on p.ID = latest.ID
inner join Transactions T on latest.ID = T.ID and latest.Last_Updated = T.Last_Updated
where p.ID in (1,2,3)
order by p.ID desc

方案3:使用窗口函数(推荐,支持绝大多数现代数据库)

通过ROW_NUMBER()窗口函数给每个产品的交易按时间倒序编号,取编号为1的最新行:

select ID, Product, Status, Last_Updated
from (
    select p.ID, p.Product, T.Status, T.Last_Updated,
           ROW_NUMBER() over (partition by p.ID order by T.Last_Updated desc) as rn
    from Products p
    inner join Transactions T on p.ID = T.ID
    where p.ID in (1,2,3)
) t
where rn = 1
order by ID desc

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 09:12:05