【问题标题】:SQL: converting multiple rows in to columns in the same rowSQL:将多行转换为同一行中的列
【发布时间】:2014-02-08 17:31:51
【问题描述】:

我需要为每节课获取每个 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(first 和 max)获取一行,但显然这些值需要在同一行中:

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

有人提供帮助吗?

【问题讨论】:

标签: mysql sql pivot


【解决方案1】:

我猜您正在使用 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 或其他接口来执行它。

【讨论】:

    【解决方案2】:

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

            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
    

    【讨论】:

      【解决方案3】:

      如果你有几个 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
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-17
        相关资源
        最近更新 更多