SQL:将多行转换为同一行中的列

时间:2014-02-08 17:31:52

标签: mysql sql pivot

我需要为每节课获得每个game_id的第一和最高分数:

--------------------------------------------
|id |lesson_id |game_id |score |date       |
--------------------------------------------
|1  |1         |0       |20    |1391627323 |
|2  |1         |0       |80    |1391627400 |
|3  |1         |1       |5     |1391627543 |
|4  |1         |2       |7     |1391627450 |
|5  |2         |0       |90    |1391627323 |
|6  |2         |1       |10    |1391628000 |
|7  |2         |2       |8     |1391628005 |
|8  |2         |2       |9     |1391628010 |
|9  |2         |0       |95    |1391628333 |
|10 |3         |0       |50    |1391627323 |
--------------------------------------------

我需要这个输出:

---------------------------------------------------
|          |game_id = 0 |game_id = 1 |game_id = 2 |
|lesson_id |first |max  |first |max  |first |max  |
---------------------------------------------------
|1         |20    |80   |5     |5    |7     |7    |
|2         |90    |95   |10    |10   |8     |9    |
|3         |50    |50   |-     |-    |-     |-    |
---------------------------------------------------

到目前为止,我有这个,每个game_id(第一个和最大)得到一行,但显然这些值需要在同一行:

SELECT game_id, lesson_id, MAX(score) AS max_score, MIN(date), score AS first_score FROM cdu_user_progress 
GROUP BY game_id 

有人提供任何帮助吗?

3 个答案:

答案 0 :(得分:0)

我猜您正在使用MySQL,因为您的示例查询在大多数其他数据库中在语法上都是不正确的。

您需要条件聚合。第一个得分很棘手:

select lesson_id,
       substring_index(group_concat(case when game_id = 1 then score end order by date),
                       ',', 1) as game1_first,
       max(case when game_id = 1 then score end) as game2_max,
       substring_index(group_concat(case when game_id = 2 then score end order by date),
                       ',', 1) as game2_first,
       max(case when game_id = 2 then score end) as game1_max,
       substring_index(group_concat(case when game_id = 3 then score end order by date),
                       ',', 1) as game3_first,
       max(case when game_id = 3 then score end) as game3_max
from cdu_user_progress 
GROUP BY lesson_id;

如果您的游戏数量未知,那么您必须将SQL构造为字符串,然后使用prepare或其他界面来执行它。

答案 1 :(得分:0)

如果你有几个game_id值,你可以尝试这样的事情:

SELECT x.lesson_id, 
       MAX(CASE WHEN x.game_id=0 THEN x.scorefirst ELSE 0 END) AS first0,
       MAX(CASE WHEN x.game_id=0 THEN y.score ELSE 0 END) AS max0,
       MAX(CASE WHEN x.game_id=1 THEN x.scorefirst ELSE 0 END) AS first1,
       MAX(CASE WHEN x.game_id=1 THEN y.score ELSE 0 END) AS max1,
       MAX(CASE WHEN x.game_id=2 THEN x.scorefirst ELSE 0 END) AS first2,
       MAX(CASE WHEN x.game_id=2 THEN y.score ELSE 0 END) AS max2,
FROM  (SELECT t1.lesson_id, t1.game_id, t1.score AS score first, t1.date
       FROM   cdu_user_progress t1 INNER JOIN
              cdu_user_progress t2 ON t1.lesson_id=t2.lesson_id
                                  AND t1.game_id =t2.game_id AND t1.date>=t2.date
        GROUP BY t1.lesson_id, t1.game_id, t1.score, t1.date
       HAVING COUNT(*)=1) x INNER JOIN
      cdu_user_progress y ON x.lesson_id=y.lesson_id AND x.game_id = y.game_id
GROUP BY x.lesson_id

否则你应该以编程方式完成

答案 2 :(得分:0)

我可能分两步完成 - 首先,我会以行格式获得结果,然后在另一个查询中使用它将它们移动到列中。

        SELECT g.lesson_id,
               g.game_id,
               c.score AS first,
               g.max_score     
         FROM (
            SELECT lesson_id, 
                   game_id,
                   MAX(score) AS max_score, 
                   MIN(date) AS min_date       
              FROM cdu_user_progress   
             GROUP BY lesson_id, game_id
            ) g     
      LEFT JOIN dbo.cdu_user_progress c
        ON g.lesson_id = c.lesson_id
       AND g.game_id = c.game_id
       AND g.min_date = c.date

不,根据您期望的列数,您可以围绕该列编写查询以将其拉入列中。注意:在SQL Server中,可能值得查看PIVOT命令。

离。

SELECT lesson_id,
       MAX(CASE WHEN p.game_id = 0
             THEN p.first 
           END) AS game_id0_first,
       MAX(CASE WHEN p.game_id = 0
             THEN p.max_score 
           END) AS game_id0_max  
      -- Add other columns here     
 FROM (
    SELECT g.lesson_id,
           g.game_id,
           c.score AS first,
           g.max_score     
      FROM (
            SELECT lesson_id, 
                   game_id,
                   MAX(score) AS max_score, 
                   MIN(date) AS min_date       
              FROM cdu_user_progress   
            GROUP BY lesson_id, game_id
            ) g     
      LEFT JOIN dbo.cdu_user_progress c
        ON g.lesson_id = c.lesson_id
       AND g.game_id = c.game_id
       AND g.min_date = c.date
   ) p
GROUP BY p.lesson_id