SQL实现多行属性值转指定列并解决左连接后多行重复问题
行转列关联查询问题解决方案
问题背景
现有两张业务表:
表A(主表)
| IDA | SomeInfo |
|---|---|
| 1 | info1 |
| 2 | info2 |
| 3 | info3 |
| 4 | info4 |
表B(属性表,键值对存储)
| IDB | IDA | VarName | VarValue |
|---|---|---|---|
| 1 | 1 | Depth | 2 |
| 2 | 1 | Length | 10 |
| 3 | 2 | Depth2 | 3 |
| 4 | 2 | Length | 12 |
| 5 | 2 | Height | 35 |
| 6 | 3 | Depth2 | 2 |
| 7 | 3 | Length | 11 |
| 8 | 3 | Height | 38 |
| 9 | 4 | Depth | 4 |
| 10 | 4 | Length | 16 |
需要关联两张表得到宽表结果:将表B中Depth和Depth2合并为同一Depth列,其余VarName作为独立列,无对应值填充0,每个IDA仅返回一行。
问题核心原因
你当前写法出现多行的本质是:B表中同一个IDA对应多条属性记录,直接左联接后每条B表记录都会生成独立结果行,仅靠DISTINCT无法合并同一IDA的多属性值,需要通过分组聚合完成行转列操作。
正确查询代码
SELECT A.IDA, A.SomeInfo, -- 合并Depth和Depth2为同一列,无值填0 COALESCE(MAX(CASE WHEN B.VarName IN ('Depth', 'Depth2') THEN B.VarValue END), 0) AS Depth, COALESCE(MAX(CASE WHEN B.VarName = 'Length' THEN B.VarValue END), 0) AS Length, COALESCE(MAX(CASE WHEN B.VarName = 'Height' THEN B.VarValue END), 0) AS Height FROM A LEFT JOIN B ON A.IDA = B.IDA AND B.VarName IN ('Depth', 'Depth2', 'Length', 'Height') -- 过滤需要处理的属性 GROUP BY A.IDA, A.SomeInfo -- 按A表主键分组,合并同一IDA的所有属性 ORDER BY A.IDA
代码说明
- 用
MAX聚合函数:同一IDA下只有匹配对应VarName的行才会返回VarValue,其余返回NULL,MAX会自动取到有效的非空值 - 用
COALESCE函数:如果聚合后结果为NULL(也就是当前IDA没有对应属性),直接替换为0,简化了CASE的嵌套写法 - 把VarName过滤条件放在JOIN的ON子句中,比子查询写法更简洁高效
- 按A表的IDA和SomeInfo分组,确保每个IDA只返回一行结果,完全匹配需要的输出格式,同时兼容DB2、AS400等数据库的语法规则。
内容的提问来源于stack exchange,提问作者ArminAH
相关产品推荐
相关产品推荐

