如何在SQL中将行数据转换为带对应值的列格式?
实现行转列(Pivot)的SQL方法
你要的这种把行数据转成列的操作叫行转列(Pivot),完全可以用SQL实现,下面给你两种常用方法:
方法一:条件聚合(通用所有SQL数据库)
这种写法兼容性最强,不管你用MySQL、PostgreSQL还是SQL Server都能跑通:
SELECT ic.company_id AS `Company ID`, ic.external_id AS `External ID`, MAX(CASE WHEN icca.attribute = 'Calls' THEN icca.int_value END) AS `Calls`, MAX(CASE WHEN icca.attribute = 'Emails' THEN icca.int_value END) AS `Emails`, MAX(CASE WHEN icca.attribute = 'Accounts' THEN icca.int_value END) AS `Accounts` FROM intercom_companies AS ic LEFT JOIN intercom_companies_custom_attributes AS icca ON ic.company_id = icca.company_id GROUP BY ic.company_id, ic.external_id;
原理说明:
CASE WHEN会根据attribute的值匹配对应的int_value,不匹配的返回NULLMAX()(或者用SUM(),这里因为每个公司对应每个attribute只有一条数据,两者效果一样)用来把同一公司的多行结果合并成一行,过滤掉NULL值GROUP BY按company_id和external_id分组,确保每个公司只出一行结果
方法二:数据库专用PIVOT语法(部分数据库支持)
如果你的数据库支持PIVOT关键字(比如SQL Server、Oracle、PostgreSQL 11+),可以用更简洁的语法:
SQL Server/Oracle版本:
SELECT company_id AS `Company ID`, external_id AS `External ID`, Calls, Emails, Accounts FROM ( SELECT ic.company_id, ic.external_id, icca.attribute, icca.int_value FROM intercom_companies AS ic LEFT JOIN intercom_companies_custom_attributes AS icca ON ic.company_id = icca.company_id ) AS source_data PIVOT ( MAX(int_value) FOR attribute IN (Calls, Emails, Accounts) ) AS pivot_table;
PostgreSQL版本(需要用crosstab函数,需先安装tablefunc扩展):
-- 先启用扩展(仅需执行一次) CREATE EXTENSION IF NOT EXISTS tablefunc; SELECT company_id AS "Company ID", external_id AS "External ID", calls, emails, accounts FROM crosstab( 'SELECT ic.company_id, ic.external_id, icca.attribute, icca.int_value FROM intercom_companies AS ic LEFT JOIN intercom_companies_custom_attributes AS icca ON ic.company_id = icca.company_id ORDER BY 1,2', 'VALUES (''Calls''), (''Emails''), (''Accounts'')' ) AS ct( company_id INT, external_id INT, calls INT, emails INT, accounts INT );
注意事项:
- 如果你的
attribute有新的值需要转成列,只需要在对应的位置新增即可(比如条件聚合里加新的CASE WHEN,PIVOT里加新的列名) - 确保每个
company_id+attribute的组合只有一条数据,避免结果出现重复或错误聚合
内容的提问来源于stack exchange,提问作者Kimberley
相关产品推荐
相关产品推荐

