将多行数据转换为含多列的单行数据(基于CARD_ID聚合角色)
解决方案:将多角色记录聚合为单行的行转列实现
首先我先假设你的原始数据表结构大概是这样的(如果实际字段名或类型有差异,你可以对应调整):
CREATE TABLE card_roles ( CARD_ID VARCHAR(50), ROLE_NAME VARCHAR(50) );
下面给你几种适配不同数据库的实现方案,你可以根据自己使用的数据库选择:
方法1:条件聚合(通用所有数据库)
这是兼容性最强的写法,不管你用MySQL、PostgreSQL还是SQL Server都能直接跑通:
SELECT CARD_ID, MAX(CASE WHEN ROLE_NAME = 'Cardholder' THEN 'X' ELSE '' END) AS Cardholder, MAX(CASE WHEN ROLE_NAME = 'Reconciler' THEN 'X' ELSE '' END) AS Reconciler, MAX(CASE WHEN ROLE_NAME = 'Approver' THEN 'X' ELSE '' END) AS Approver FROM card_roles GROUP BY CARD_ID;
核心思路是:按CARD_ID分组后,用CASE语句判断当前行的角色是否匹配目标列,匹配就标记(这里用X,你也可以换成角色名称或其他需要的值),不匹配就留空;最后用MAX(或MIN,因为同一角色在同一CARD_ID下只会有一条有效记录)聚合出单行结果。
方法2:数据库原生PIVOT语法(以SQL Server/Oracle为例)
如果你的数据库支持原生的PIVOT语法,可以用更简洁的写法:
SELECT CARD_ID, ISNULL(Cardholder, '') AS Cardholder, ISNULL(Reconciler, '') AS Reconciler, ISNULL(Approver, '') AS Approver FROM ( SELECT CARD_ID, ROLE_NAME FROM card_roles ) AS SourceTable PIVOT ( MAX(ROLE_NAME) -- PIVOT必须搭配聚合函数,因为同一分组下可能有重复值,这里用MAX不影响结果 FOR ROLE_NAME IN (Cardholder, Reconciler, Approver) ) AS PivotTable;
这里用ISNULL把默认的NULL转换成空字符串,满足你“无对应角色留空”的要求。
方法3:PostgreSQL专属的crosstab函数
如果你使用PostgreSQL,可以借助tablefunc扩展里的crosstab函数来实现:
首先需要先启用扩展(仅需执行一次):
CREATE EXTENSION IF NOT EXISTS tablefunc;
然后执行查询:
SELECT CARD_ID, COALESCE(Cardholder, '') AS Cardholder, COALESCE(Reconciler, '') AS Reconciler, COALESCE(Approver, '') AS Approver FROM crosstab( 'SELECT CARD_ID, ROLE_NAME, ROLE_NAME FROM card_roles ORDER BY 1', 'VALUES (''Cardholder''), (''Reconciler''), (''Approver'')' ) AS ct(CARD_ID VARCHAR, Cardholder VARCHAR, Reconciler VARCHAR, Approver VARCHAR);
COALESCE在这里的作用和ISNULL一样,把NULL转为空字符串。
补充小提示
如果你的原始表中同一个CARD_ID可能存在重复的角色记录,上述方法中的聚合函数会自动帮你去重,不会影响最终结果;如果需要展示的不是标记,而是角色对应的其他关联字段(比如用户名),只需要把CASE或PIVOT里的ROLE_NAME换成对应的字段即可。
内容的提问来源于stack exchange,提问作者Katie
相关产品推荐
相关产品推荐

