如何实现LEFT JOIN仅为每个FUND_ID匹配首行数据?
实现保留全量行且仅每个分组首行关联数据的SQL方案
适用现代数据库(支持窗口函数:PostgreSQL、MySQL 8.0+、SQL Server等)
核心思路是用窗口函数ROW_NUMBER()给每个FUND_ID分组内的行编号,标记出首行,再仅让首行关联dt2的匹配数据:
SELECT dt1.FUND_ID, dt1.Name, CASE WHEN rn = 1 THEN dt2.Value ELSE NULL END AS Value FROM ( -- 给每个FUND_ID分组的行按指定顺序编号,首行编号为1 SELECT FUND_ID, Name, ROW_NUMBER() OVER (PARTITION BY FUND_ID ORDER BY Name) AS rn FROM dt1 ) dt1 -- 仅首行(rn=1)与dt2关联 LEFT JOIN dt2 ON dt1.FUND_ID = dt2.FUND_ID AND dt1.rn = 1 ORDER BY dt1.FUND_ID, dt1.rn;
说明:
ORDER BY Name是定义"首行"的规则,如果你需要按其他逻辑(比如创建时间、主键顺序)确定首行,替换成对应的字段即可(比如ORDER BY create_time)。- 执行后每个
FUND_ID的首行会匹配dt2的Value,其他行Value为NULL,完全符合预期结果。
适用老版本数据库(不支持窗口函数:MySQL 5.7及以前等)
如果数据库不支持窗口函数,可以用子查询标记每个分组的首行:
SELECT dt1.FUND_ID, dt1.Name, -- 仅当当前行是分组首行时取dt2的Value,否则为NULL CASE WHEN dt1.Name = (SELECT MIN(Name) FROM dt1 d WHERE d.FUND_ID = dt1.FUND_ID) THEN dt2.Value ELSE NULL END AS Value FROM dt1 LEFT JOIN dt2 ON dt1.FUND_ID = dt2.FUND_ID ORDER BY dt1.FUND_ID, dt1.Name;
说明:
MIN(Name)用来确定每个FUND_ID的首行(取Name最小的行),如果需要其他首行规则,替换成对应的聚合函数和字段(比如MIN(create_time))。
内容的提问来源于stack exchange,提问作者Gil Silva
相关产品推荐
相关产品推荐

