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
答案 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
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
的值,否则评估为NULL
。 max
聚合器只会忽略NULL
值。
编辑:在第二个查询中添加警告,以解释使用生成的查询的警告,感谢Mike Brant的评论