如何用SQL从关联的Header与Details表中仅获取每条Header对应一条Detail记录?
需求:获取每个Header对应的第一条Detail记录
现有表结构及数据
Header表
ID Name Address ----------------------------- 1000 Header 1 Address 1 1010 Header 2 Address 2 1020 Header 3 Address 3 1030 Header 4 Address 4 1040 Header 5 Address 5
Details表
DetailID HeaderID DetailDesc DetailType ------------------------------------------------------ 1000-1 1000 Detail 1 Type 1 1000-2 1000 Detail 2 Type 2 1000-3 1000 Detail 3 Type 3 1010-1 1010 Detail 4 Type 1 1020-1 1020 Detail 5 Type 1 1020-2 1020 Detail 6 Type 2 1030-1 1030 Detail 7 Type 1 1030-2 1030 Detail 8 Type 2
期望查询结果
需要获取每个Header匹配的第一条Detail记录,结果如下:
ID DetailID Name Address ------------------------------------------ 1000 1000-1 Header 1 Address 1 1010 1010-1 Header 2 Address 2 1020 1020-1 Header 3 Address 3 1030 1030-1 Header 4 Address 4
当前问题
使用以下SQL查询会返回全部8条Detail记录,无法满足每个Header仅对应一条Detail的需求:
SELECT H.ID, D.HeaderID, H.Name, H.Address FROM Header AS H JOIN Details AS D ON H.ID = D.HeaderID
解决方案
方法1:使用窗口函数(推荐,兼容性好)
通过ROW_NUMBER()窗口函数按HeaderID分组,给每个分组内的记录按DetailID排序并编号,筛选出编号为1的记录即可:
SELECT ID, DetailID, Name, Address FROM ( SELECT H.ID, D.DetailID, H.Name, H.Address, ROW_NUMBER() OVER (PARTITION BY H.ID ORDER BY D.DetailID) AS rn FROM Header AS H JOIN Details AS D ON H.ID = D.HeaderID ) AS t WHERE rn = 1;
方法2:关联子查询取最小DetailID
若数据库不支持窗口函数,可通过子查询找到每个HeaderID对应的最小DetailID,再关联查询:
SELECT H.ID, D.DetailID, H.Name, H.Address FROM Header AS H JOIN Details AS D ON H.ID = D.HeaderID WHERE D.DetailID = ( SELECT MIN(DetailID) FROM Details WHERE HeaderID = H.ID );
说明
- 窗口函数方式更灵活,若后续需调整排序规则(比如按记录创建时间排序),只需修改
ORDER BY后的字段即可。 - 子查询方式适用于不支持窗口函数的老旧数据库版本。
内容的提问来源于stack exchange,提问作者Achu
相关产品推荐
相关产品推荐

