如何在SQL查询中实现行转列,按User ID分组展示分类支出与交易数据?
SQL行列转换:将Category对应的Spend和Transactions转为单独列
通用解决方案(适用于多数SQL数据库)
如果已知所有可能的Category取值,直接用CASE WHEN配合聚合函数就能实现需求,这是最直观且兼容性最好的方法:
SELECT `User ID`, Country, -- 处理Sport类别的支出和交易数 SUM(CASE WHEN Category = 'Sport' THEN Spend ELSE 0 END) AS Sport_Spend, SUM(CASE WHEN Category = 'Sport' THEN Transactions ELSE 0 END) AS Sport_Transactions, -- 处理Bills类别的支出和交易数 SUM(CASE WHEN Category = 'Bills' THEN Spend ELSE 0 END) AS Bills_Spend, SUM(CASE WHEN Category = 'Bills' THEN Transactions ELSE 0 END) AS Bills_Transactions, -- 可根据实际Category继续扩展 SUM(CASE WHEN Category = 'Entertainment' THEN Spend ELSE 0 END) AS Entertainment_Spend, SUM(CASE WHEN Category = 'Entertainment' THEN Transactions ELSE 0 END) AS Entertainment_Transactions FROM user_spending GROUP BY `User ID`, Country;
关键逻辑说明:
CASE WHEN判断当前行的Category是否匹配目标类别,匹配则取对应字段值,否则返回0SUM按User ID和Country分组聚合,自动将同一用户同一类别的数值累加;无对应类别时,累加的都是0,正好满足"无数据填0"的要求- 同一
User ID对应的Country应唯一,分组时包含Country即可保留该字段,无需额外处理
动态生成列(适用于Category取值不确定的场景)
如果Category的取值会动态变化,不想每次新增类别都修改SQL,可以用动态SQL实现,以下是MySQL的示例:
-- 拼接动态SQL语句 SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'SUM(CASE WHEN Category = ''', Category, ''' THEN Spend ELSE 0 END) AS ', Category, '_Spend, SUM(CASE WHEN Category = ''', Category, ''' THEN Transactions ELSE 0 END) AS ', Category, '_Transactions' ) ) INTO @sql FROM user_spending; -- 组装完整查询语句并执行 SET @sql = CONCAT('SELECT `User ID`, Country, ', @sql, ' FROM user_spending GROUP BY `User ID`, Country'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
逻辑说明:
- 通过
GROUP_CONCAT自动获取所有唯一的Category值,拼接出对应的CASE WHEN语句块 - 动态生成完整的SQL后,通过预处理语句执行,实现自动适配所有现有Category
其他数据库的动态实现逻辑类似:
- SQL Server可结合
PIVOT和动态SQL - PostgreSQL可使用
crosstab函数或动态SQL拼接
内容的提问来源于stack exchange,提问作者Count
相关产品推荐
相关产品推荐

