在mysql中为每个不同的值为每种数据类型选择几种最大类型

时间:2014-11-24 22:12:51

标签: mysql max distinct

userid      data_type,          timespentaday
 1       League of Legends          500
 1       Hearthstone                1500
 1       Hearthstone                1400
 2       World of Warcraft          1200
 1       Dota 2                     100
 2       Final Fantasy              500
 1       Dota 2                     700

鉴于此数据。我想查询每个用户花在每个上面的最多时间。

所需输出:

User    League Of Legends    Hearthstone   World of Warcraft     Dota 2    
 1           500                1500             0                  700
 2           0                  0                1200               0

我所尝试过的一些事情

SELECT t1.* FROM user_info GROUP BY userid JOIN(
 SELECT(
         (SELECT max(timespentaday) where data_type='League of Legends'),
          (SELECT max(timespentaday) where data_type='Hearhstone'),
          (SELECT max(timespentaday) where data_type='Dota 2)'
FROM socialcount AS t2
) as t2
ON t1.userid = t2.userid

3 个答案:

答案 0 :(得分:2)

基本上要做到这一点你需要每组最大的n ..有一篇很好的文章,但是要点在mysql中你必须使用变量甚至接近这个...特别是在表上做一个转轴(因为MySQL没有本机支持,所以这是一个虚假的支点。)

SELECT userid,
    MAX(CASE WHEN data_type = "League of Legends" THEN timespentaday ELSE 0 END) as "League of Legends",
    MAX(CASE WHEN data_type = "Hearthstone" THEN timespentaday ELSE 0 END) as "Hearthstone",
    MAX(CASE WHEN data_type = "Dota 2" THEN timespentaday ELSE 0 END) as "Dota 2",
    MAX(CASE WHEN data_type = "World of Warcraft" THEN timespentaday ELSE 0 END) as "World of Warcraft",
    MAX(CASE WHEN data_type = "Final Fantasy" THEN timespentaday ELSE 0 END) as "Final Fantasy"
FROM
(   SELECT *, @A := if(@B = userid, if(@C = data_type, @A + 1, 1), 1) as count_to_use, @B := userid, @C := data_type
    FROM
    (   SELECT userid, timespentaday, data_type
        FROM gamers
        CROSS JOIN(SELECT @A := 0, @B := 0, @C := '') temp
        ORDER BY userid ASC, data_type ASC, timespentaday DESC
    ) t
    HAVING count_to_use = 1
)t1
GROUP BY userid

DEMO

注意:

MySQL DOCS对于使用用户定义变量的警告非常明确:

  

作为一般规则,您不应该为用户变量赋值   并在同一语句中读取值。你可能会得到   你期望的结果,但这不能保证。的顺序   涉及用户变量的表达式的评估是未定义的   可能会根据给定声明中包含的元素进行更改;   另外,这个顺序不保证是相同的   MySQL服务器的版本。在SELECT @ a,@ a:= @ a + 1,...,你可以   认为MySQL会首先评估@a然后做一个任务   第二。但是,更改语句(例如,通过添加   GROUP BY,HAVING或ORDER BY子句可能导致MySQL选择一个   执行计划具有不同的评估顺序。

答案 1 :(得分:1)

我不会给你一个你想要的输出格式的查询,因为实现该数据透视表将是一个非常丑陋和表现不佳的查询,以及不可扩展的东西,因为不同的游戏数量增加。

相反,我将重点介绍如何以最直接的方式查询数据,以及如何将其读入数据结构,应用程序逻辑将根据需要使用该数据结构来创建数据透视视图。

首先是查询:

SELECT
  userid,
  data_type,
  MAX(timespentaday) AS max_timespent
FROM social_count
GROUP BY userid, data_type

这会产生类似

的结果
userid    data_type               max_timespent
------    ---------               -------------
1         League of Legends       500
1         Hearthstone             1500
1         Dota 2                  700
2         World of Warcraft       1200
2         Final Fantasy           500

现在,当从数据库中读取结果时,您只需将其读入一个有用的结构中。我将使用PHP作为示例语言,但这应该可以轻松移植到任何语言

// will hold distinct list of all available games
$games_array = array();
// will hold user data from DB
$user_data = array();
while ($row = /* your database row fetch mechanism here */) {
    // update games array as necessary
    if (!in_array($row['data_type'], $games_array)) {
        // add this game to $games_array as it does not exist there yet
        $games_array[] = $row['data_type'];
    }
    // update users array
    $users[$row['userid']][$row['data_type']] = $row['max_timespent'];
}

// build pivot table
foreach($users as $id => $game_times) {
    // echo table row start
    // echo out user id in first element
    // then iterate through available games
    foreach($games_array as $game) {
        if(!empty($game_times[$game])) {
            // echo $game_times['game'] into table element
        } else {
            // echo 0 into table element
        }
    }
    // echo table row end
}

答案 2 :(得分:0)

您将无法使用动态列数构建查询。如果您已经知道游戏列表,则可以执行此查询,我猜这不是您需要的。 但是,您始终可以使用任何编程语言对结果进行后处理,因此您只需要检索数据。

SQL查询看起来像这样:

SELECT
  userid AS User,
  data_type AS Game,
  max(timespentaday) AS TimeSpentADay
FROM
  my_table
GROUP BY
  userid
  data_type

然后迭代结果以填充您想要的任何界面

OR

当且仅当您无法承担任何类型的后期处理时,您可以首先检索游戏列表,然后您可以构建查询,如下面的查询。请记住,这个查询比以前的查询要少得多(除了更难以构建之外),并且可能会在以后的调试中引起很多痛苦。

SELECT
  userid AS User,
  max(CASE 
    WHEN data_type = 'Hearthstone' THEN timespentaday 
    ELSE NULL 
  END) AS Hearthstone,
  max(CASE 
    WHEN data_type = 'League Of Legends' THEN timespentaday 
    ELSE NULL 
  END) AS `League Of Legends`,
  ...
FROM
  my_table
GROUP BY
  userid

CASE contstruction就像程序编程语言中的if,以下

CASE 
    WHEN data_type = 'League Of Legends' THEN timespentaday 
    ELSE NULL 
END

如果游戏是英雄联盟,则评估为timespentaday的值,否则评估为NULLmax聚合器只会忽略NULL值。

编辑:在第二个查询中添加警告,以解释使用生成的查询的警告,感谢Mike Brant的评论