Oracle SQL关联分类与子分类表后,如何实现主分类列仅显示一次?
如何在SQL查询结果中让主分类仅显示一次(避免重复)
我将分类与子分类存储在不同的表中,关联查询后得到的结果表中主分类行重复显示:
| Col1 | Col2 | Col3 | Col4 |
|---|---|---|---|
| Cat1 | Cat1 Data | Subcat 1.1 | Etc |
| Cat1 | Cat1 Data | Subcat 1.2 | Etc |
| Cat1 | Cat1 Data | Subcat 1.3 | Etc |
| Cat2 | Cat2 Data | Subcat 2.1 | Etc |
| Cat2 | Cat2 Data | Subcat 2.2 | Etc |
| Cat2 | Cat2 Data | Subcat 2.3 | Etc |
我希望实现如下显示效果,让主分类仅在每组的第一行显示,后续行对应的主分类列留空:
| Col1 | Col2 | Col3 | Col4 |
|---|---|---|---|
| Cat1 | Cat1 Data | Subcat 1.1 | Etc |
| Subcat 1.2 | Etc | ||
| Subcat 1.3 | Etc | ||
| Cat2 | Cat2 Data | Subcat 2.1 | Etc |
| Subcat 2.2 | Etc | ||
| Subcat 2.3 | Etc |
我试过DISTINCT和GROUP BY的方案,但不符合我的使用场景;而且我无法使用前端工具来处理显示,必须在SQL层面实现这个效果。
解决方案:用窗口函数标记分组行号来控制显示
这是报表类查询里很常见的需求,既然没法用前端处理,完全可以在SQL层面搞定,核心思路是给每个主分类组内的行编个号,只在组内第一行显示主分类内容,其他行留空。
主流数据库方案(MySQL 8+/PostgreSQL/SQL Server)
假设你的基础关联查询是这样的:
SELECT c.col1, c.col2, s.col3, s.col4 FROM categories c JOIN subcategories s ON c.id = s.category_id ORDER BY c.col1, s.col3;
你可以嵌套一个子查询,用ROW_NUMBER()窗口函数给每组主分类的行排序编号,然后在外层用CASE判断来控制显示:
SELECT -- 仅在组内第一行显示主分类Col1,其余行留空 CASE WHEN row_num = 1 THEN col1 ELSE '' END AS col1, -- 同理处理Col2 CASE WHEN row_num = 1 THEN col2 ELSE '' END AS col2, col3, col4 FROM ( SELECT c.col1, c.col2, s.col3, s.col4, -- 按主分类分组,组内按子分类排序,生成行号 ROW_NUMBER() OVER (PARTITION BY c.col1 ORDER BY s.col3) AS row_num FROM categories c JOIN subcategories s ON c.id = s.category_id ) AS grouped_data -- 保持排序,确保结果顺序正确 ORDER BY col1, row_num;
旧版MySQL(低于8.0)兼容方案
如果你的MySQL版本不支持窗口函数,可以用用户变量来模拟这个逻辑:
-- 初始化变量,追踪上一行的主分类和当前组内的行号 SET @prev_cat = ''; SET @row_num = 1; SELECT CASE WHEN col1 = @prev_cat THEN '' ELSE col1 END AS col1, CASE WHEN col1 = @prev_cat THEN '' ELSE col2 END AS col2, col3, col4 FROM ( SELECT c.col1, c.col2, s.col3, s.col4 FROM categories c JOIN subcategories s ON c.id = s.category_id ORDER BY c.col1, s.col3 ) AS sorted_data, (SELECT @prev_cat := '', @row_num := 1) AS init_vars -- 用变量更新逻辑,确保行号正确 HAVING @row_num := IF(col1 = @prev_cat, @row_num + 1, 1) AND @prev_cat := col1;
这个方法通过用户变量记录上一行的主分类,判断当前行是否属于同一组,从而决定是否显示主分类内容。
注意点
- 如果你希望空值显示为
NULL而不是空字符串,把ELSE ''改成ELSE NULL即可。 - 排序条件
ORDER BY s.col3可以根据你的实际需求调整,比如按子分类ID排序,确保组内行的顺序符合预期。
内容的提问来源于stack exchange,提问作者RedRaven
相关产品推荐
相关产品推荐

