MySQL 8.0版本下使用Pivot实现两表关联的查询方案求助
解决MySQL动态Pivot实现需求
首先看你的问题,核心是要把t2表中按sUn分组的sContents,以sUnName作为列名,按行号对齐展示——也就是每个sUn下的第1条、第2条、第3条内容分别对应结果的每一行。
分析你之前的问题
- 第一个SQL的语法错误:你写的
max( IF ( t.sUn = q.TABLE_NAME, t.sContents, NULL )) q.sUnName语法不对,别名应该放在表达式后面(比如AS q.sUnName),更关键的是静态SQL无法处理动态列名,因为sUnName的值是可变的,没法提前写死。 - 存储过程的结果不符合预期:你的存储过程没有按行号分组,只是简单生成了CASE语句,导致每个
sContents单独占一行,没有把同序号的内容聚合到同一行。
正确的实现方案
因为列名(NOR、SAR等)是动态的,必须用动态SQL来生成对应的列。下面是两种可行的方式:
方式一:直接用预处理语句执行
-- 设置GROUP_CONCAT的最大长度,避免SQL被截断 SET SESSION group_concat_max_len = 1000000; SET @sql = NULL; -- 生成每个sUnName对应的CASE聚合语句 SELECT GROUP_CONCAT(DISTINCT CONCAT( 'MAX(CASE WHEN sUnName = ''', sUnName, ''' THEN sContents END) AS `', sUnName, '`' ) ) INTO @sql FROM t2; -- 拼接完整的SQL:先给t2的每行按sUn分组生成行号,再按行号聚合 SET @sql = CONCAT('SELECT ', @sql, ' FROM ( SELECT sUnName, sContents, ROW_NUMBER() OVER (PARTITION BY sUn ORDER BY sid) AS rn FROM t2 ) AS t GROUP BY rn ORDER BY rn;'); -- 执行动态SQL PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
方式二:封装成存储过程(方便重复调用)
CREATE DEFINER=`root`@`localhost` PROCEDURE `pivot_t2`() BEGIN SET SESSION group_concat_max_len = 1000000; SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'MAX(CASE WHEN sUnName = ''', sUnName, ''' THEN sContents END) AS `', sUnName, '`' ) ) INTO @sql FROM t2; SET @sql = CONCAT('SELECT ', @sql, ' FROM ( SELECT sUnName, sContents, ROW_NUMBER() OVER (PARTITION BY sUn ORDER BY sid) AS rn FROM t2 ) AS t GROUP BY rn ORDER BY rn;'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END
调用存储过程:
CALL pivot_t2();
方案说明
- ROW_NUMBER()窗口函数:给每个
sUn分组下的行生成序号(rn),确保每个sUn的内容按sid顺序排列,对应结果的每一行。 - 动态列生成:用
GROUP_CONCAT自动生成所有sUnName对应的MAX(CASE...)语句,避免手动写死列名。 - 按行号分组:通过
GROUP BY rn把同一序号的不同sUn的内容聚合到同一行,正好符合你的预期结果。
执行后就能得到你想要的输出格式了。
内容的提问来源于stack exchange,提问作者Edward Sheriff Curtis
相关产品推荐
相关产品推荐

