如何将同一TRIP的多行数据合并为单行并保留Flag值?
当然有办法搞定这个需求!这种把同一Trip的多行Flag合并成单行的场景,在SQL里是很常见的操作,核心就是按Trip分组后,对每个Flag列做聚合处理,把非空的'Y'保留下来。下面给你几种实用的实现方案:
最直观且通用的方法是使用聚合函数MAX()——因为MAX()会自动忽略NULL值,只保留同一Trip下对应Flag列的'Y'(如果存在的话)。
假设你的Flag列分别是Flag1、Flag2、Flag3、Flag4(对应你示例中的列),直接执行以下SQL即可得到目标Table B:
SELECT Trip, MAX(Flag1) AS Flag1, MAX(Flag2) AS Flag2, MAX(Flag3) AS Flag3, MAX(Flag4) AS Flag4 FROM TableA GROUP BY Trip;
这个逻辑非常清晰:按Trip分组后,每个Flag列取最大值(由于'Y'是唯一非空值,MAX自然会选中它),同时自动剔除了不需要的StaffNo和Doc字段。
如果你的Flag列数量特别多,或者需要更灵活的处理,可以参考以下数据库专属方案:
MySQL 8.0+
可以用JSON_OBJECTAGG动态拼接Flag列,避免手动写大量MAX():
SELECT Trip, JSON_UNQUOTE(JSON_EXTRACT(agg_flags, '$.Flag1')) AS Flag1, JSON_UNQUOTE(JSON_EXTRACT(agg_flags, '$.Flag2')) AS Flag2, JSON_UNQUOTE(JSON_EXTRACT(agg_flags, '$.Flag3')) AS Flag3, JSON_UNQUOTE(JSON_EXTRACT(agg_flags, '$.Flag4')) AS Flag4 FROM ( SELECT Trip, JSON_OBJECTAGG(flag_col, flag_val) AS agg_flags FROM ( -- 先把列转行,方便聚合 SELECT Trip, 'Flag1' AS flag_col, Flag1 AS flag_val UNION ALL SELECT Trip, 'Flag2', Flag2 UNION ALL SELECT Trip, 'Flag3', Flag3 UNION ALL SELECT Trip, 'Flag4', Flag4 ) unpivoted WHERE flag_val IS NOT NULL -- 只保留非空的Flag值 GROUP BY Trip ) aggregated;
不过如果列数不多,还是第一种GROUP BY + MAX()的方法更简洁高效。
SQL Server
可以用PIVOT函数实现,但其实直接用通用方案的MAX()已经足够简单。如果想尝试PIVOT,可以参考:
SELECT Trip, Flag1, Flag2, Flag3, Flag4 FROM TableA PIVOT ( MAX(Flag1) FOR Flag1 IN ([Flag1]), MAX(Flag2) FOR Flag2 IN ([Flag2]), MAX(Flag3) FOR Flag3 IN ([Flag3]), MAX(Flag4) FOR Flag4 IN ([Flag4]) ) AS PivotResult;
但显然,直接写GROUP BY + MAX()的代码量更少,可读性更强。
Oracle
Oracle同样支持GROUP BY + MAX()的通用方案,也可以用PIVOT函数:
SELECT Trip, Flag1, Flag2, Flag3, Flag4 FROM ( SELECT Trip, 'Flag1' AS flag_type, Flag1 AS flag_val FROM TableA UNION ALL SELECT Trip, 'Flag2', Flag2 FROM TableA UNION ALL SELECT Trip, 'Flag3', Flag3 FROM TableA UNION ALL SELECT Trip, 'Flag4', Flag4 FROM TableA ) PIVOT ( MAX(flag_val) FOR flag_type IN ('Flag1' AS Flag1, 'Flag2' AS Flag2, 'Flag3' AS Flag3, 'Flag4' AS Flag4) );
这里需要先将列转为行,不过通用方案依然是最省心的选择。
拿你提到的前3行数据举例:
TableA中Trip=1的3行分别对应Flag1='Y'、Flag2='Y'、Flag3='Y',其余Flag为NULL
执行通用方案的SQL后,得到的Table B中Trip=1的行就是:Trip=1, Flag1='Y', Flag2='Y', Flag3='Y', Flag4=NULL,完全匹配你想要的结果。
内容的提问来源于stack exchange,提问作者B.Dick

