将行转置为没有确切列数的列

时间:2014-08-14 09:39:20

标签: mysql sql

我的桌子名称和分数如下所示:

+---------+---------+
| Name    | Score   | 
+---------+---------+
|  Joe    | 1       |  
+---------+---------+
|  Joe    | 4       |  
+---------+---------+
|  Joe    | 2       |  
+---------+---------+
|  Joe    | 5       |  
+---------+---------+
|  Steve  | 4       |  
+---------+---------+
|  Steve  | 2       |  
+---------+---------+
|  Steve  | 1       |  
+---------+---------+

输出要求是将行转置为列,因此结果表应如下所示:

+--------+---------+---------+---------+---------+
| Joe    |   1     |    4    |    2    |    5    |  
+--------+---------+---------+---------+---------+  
| Steve  |   4     |    2    |    1    |         |
+--------+---------+---------+---------+---------+ 

问题是你看不到相同数量的行。对于Joe来说,有4行,而Steve有3行。

是否可以将行转换为列而不知道输出中应该有多少列?

2 个答案:

答案 0 :(得分:0)

最简单的方法是省去单独的列,只使用group_concat()。这会将得分放在一列中,并带有分隔符:

select name, group_concat(score) as scores
from table t
group by name;

SQL语句不能具有可变数量的输出列。您需要在select中指定每个列。如果你有一个最大值,比如说5,你可以枚举值,然后转动:

select name,
       max(case when rn = 1 then score end) as score_1,
       max(case when rn = 2 then score end) as score_2,
       max(case when rn = 3 then score end) as score_3,
       max(case when rn = 4 then score end) as score_4,
       max(case when rn = 5 then score end) as score_5
from (select t.*,
             (@rn := if(@name = name, @rn + 1, if (@name := name, 1, 1))) as rn
      from table t cross join
           (select @rn := 0, @name := '') vars
      order by name
     ) t
group by name;

如果你想要一个可变数量的列,你可以使用动态SQL(即准备好的语句)做类似的事情。

答案 1 :(得分:0)

我试过这样:检查一下

nam是姓名 val是得分

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(CASE WHEN val = ''',
      val,
      ''' THEN val END) AS `',
      (SELECT              ( 
                CASE nam 
                WHEN @curType 
                THEN @curRow := @curRow + 1 
                ELSE @curRow := 1 AND @curType := nam END
              ) + 1 AS rank
    FROM      tab1 p,
              (SELECT @curRow := 0, @curType := '') r
       where p.val=t.val and p.nam=t.nam
), '`'
    )
  ) INTO @sql
FROM tab1 t;


SET @sql 
  = CONCAT('SELECT p.nam, ', @sql, ' 
           from tab1 p
           group by p.nam');

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

Sql Fiddle