在MySQL中将行转换为列

时间:2019-05-28 14:41:44

标签: mysql sql

我的表来自存储过程的输出。看起来像:

col1 
A 
B
C
D

它可以少于或等于5行。
我希望它看起来像这样

Column1  Column2 Column3  Column4  column5 
A          B      C         D       NULL

在MYSQL中有没有办法实现这一目标?

2 个答案:

答案 0 :(得分:2)

在MySQL 8+中,使用ROW_NUMBER和数据透视查询是一种相当简单的方法:

WITH cte AS (
    SELECT col1, ROW_NUMBER() OVER (ORDER BY col1) rn
    FROM yourTable
)

SELECT
    MAX(CASE WHEN rn = 1 THEN col1 END) AS Column1,
    MAX(CASE WHEN rn = 2 THEN col1 END) AS Column2,
    MAX(CASE WHEN rn = 3 THEN col1 END) AS Column3,
    MAX(CASE WHEN rn = 4 THEN col1 END) AS Column4,
    MAX(CASE WHEN rn = 5 THEN col1 END) AS Column5
FROM cte;

答案 1 :(得分:2)

在MySQL 8.0以下,此方法变得更加复杂。

关于第一个查询的难点的简单解释
内的子查询

  SELECT 
     GROUP_CONCAT(t.col1 ORDER BY col1 ASC) AS cvs
   , COUNT(*) AS t_count
  FROM 
   t

正在创建一个用逗号分隔的值列表。 然后,将SQL数字生成器与嵌套的SUBSTRING_INDEX()函数结合使用,将逗号分隔的值拆分为记录。 然后GROUP_CONCAT()将其合并为一个字符串,并最终转化为用户变量,基本上是在生成动态SQL时看起来像'<value>' AS Column<number>[, ...]SELECT @aggregateSQLPart;会向您显示

查询

SET @aggregateSQLPart = NULL; 

# set max of GROUP_CONCAT higher as it defaults to 1024 bytes. 
SET SESSION group_concat_max_len = @@max_allowed_packet;

SELECT 
 DISTINCT
   GROUP_CONCAT(CONCAT("'", 
    SUBSTRING_INDEX(
       SUBSTRING_INDEX(
          t.cvs
         , ','
       , number_generator.number
      )
      , ','
      , -1 
    ) , "'" , " AS Column", number_generator.number 
 ))
INTO @aggregateSQLPart                          
FROM (
   SELECT 
     @row := @row + 1 AS number
   FROM (
      SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION   SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
      ) row1
      CROSS JOIN (
      SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION  SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9
    ) row2
    CROSS JOIN (
      SELECT @row := 0 
    ) init_user_params 
  ) AS number_generator
 CROSS JOIN (
  SELECT 
     GROUP_CONCAT(t.col1 ORDER BY col1 ASC) AS cvs
   , COUNT(*) AS t_count
  FROM 
   t
 ) AS t

WHERE
 number BETWEEN 1 AND t_count;

SELECT @aggregateSQLPart;    


SET @SQL = CONCAT("
 SELECT 
 "
 , @aggregateSQLPart                                                 
);

SELECT @SQL;    

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

结果

| Column1 | Column2 | Column3 | Column4 | Column5 |
| ------- | ------- | ------- | ------- | ------- |
| A       | B       | C       | D       | E       |

请参阅demo

注意,不要怀疑它在“测试”服务器上平均运行大约5-10 ms的性能。也请注意,我选择了用户变量,因此您可以看到有什么不足之处在两者之间。