MySQL总排名,按流派分组,限10
MySQL sum ranking, group by genre, limit 10
我有 MySQL table 这样的,我想计算每个流派的 TOP10:
- rankings_2016 (trackId, genreId, ranking, timestamp)
- 流派 (genreId, genreName)
- tracks (trackId, trackName, genreId)
- 艺术家(artistId, artistName)
- artists_tracks (artistId, trackId)
我想获得每个流派、每个曲目和每个艺术家的 TOP10 排名。
一首曲目或一位艺术家最多可以有 2 种流派。排名可能是一样的。只是为了了解 LIMIT 2 的想法:
genreId | trackId | ranking
---------------------------------
0 1111 100
0 2222 99
1 1111 100
1 2222 99
genreId | artistId | ranking
---------------------------------
0 1111 100
0 2222 99
1 1111 100
1 2222 99
我找到的唯一解决方案是将所有内容都放在 table 中,然后在页面中限制 10 个,但它会占用我的数据库大小(我的资源有限)。
对于我写的曲目:
SELECT trackId, genreId, @newRank := SUM(ranking) as ranking
FROM rankings_2016
WHERE timestamp >= ( select unix_timestamp('2016-01-01') )
AND timestamp <= ( select unix_timestamp('2016-12-31') )
GROUP BY trackId, genreId
对于艺术家:
SELECT artistId, genreId, @newRank := SUM(a1.ranking) as ranking
FROM rankings_2016 a1
LEFT JOIN artists_tracks a2
ON a1.trackId = a2.trackId
WHERE timestamp >= ( select unix_timestamp('2016-01-01') )
AND timestamp <= ( select unix_timestamp('2016-12-31') )
GROUP BY artistId, genreId
提前感谢大家的提示。
更新
一般逻辑(和接受的回复)需要良好的索引和高性能的服务器。
在我的案例中,ARTISTS 失败并出现错误 500,除非我增加 CPU。
通常用 INNER 替换 LEFT 可以节省 1 秒。
考虑一个相关的计数子查询,以按艺术家/曲目/流派分组对排名进行排序。然后在外部查询中使用此 rank 计算列过滤每个分组的前 10 个:
艺术家排名(每个艺术家和流派的前 10 名排名)
SELECT main.artistId, main.genreId, main.ranking
FROM
(
SELECT a.artistId, r.genreId, r.ranking,
(SELECT COUNT(*) FROM rankings_2016 subr
LEFT JOIN artists_tracks suba ON subr.trackId = suba.trackId
WHERE suba.artistId = a.artistId
AND subr.genreId = r.genreId
AND subr.ranking >= r.ranking) AS rn
FROM rankings_2016 r
LEFT JOIN artists_tracks a ON r.trackId = a.trackId
WHERE r.timestamp BETWEEN ( select unix_timestamp('2016-01-01') )
AND ( select unix_timestamp('2016-12-31') )
) AS main
WHERE main.rn <= 10
曲目排名(每个曲目和流派的前 10 名)
SELECT main.trackId, main.genreId, main.ranking
FROM
(
SELECT r.trackId, r.genreId, r.ranking,
(SELECT COUNT(*) FROM rankings_2016 subr
WHERE subr.genreId = r.genreId
AND subr.trackId = r.trackId
AND subr.ranking >= r.ranking) AS rn
FROM rankings_2016 r
WHERE r.timestamp BETWEEN ( select unix_timestamp('2016-01-01') )
AND ( select unix_timestamp('2016-12-31') )
) AS main
WHERE main.rn <= 10
我有 MySQL table 这样的,我想计算每个流派的 TOP10:
- rankings_2016 (trackId, genreId, ranking, timestamp)
- 流派 (genreId, genreName)
- tracks (trackId, trackName, genreId)
- 艺术家(artistId, artistName)
- artists_tracks (artistId, trackId)
我想获得每个流派、每个曲目和每个艺术家的 TOP10 排名。
一首曲目或一位艺术家最多可以有 2 种流派。排名可能是一样的。只是为了了解 LIMIT 2 的想法:
genreId | trackId | ranking
---------------------------------
0 1111 100
0 2222 99
1 1111 100
1 2222 99
genreId | artistId | ranking
---------------------------------
0 1111 100
0 2222 99
1 1111 100
1 2222 99
我找到的唯一解决方案是将所有内容都放在 table 中,然后在页面中限制 10 个,但它会占用我的数据库大小(我的资源有限)。
对于我写的曲目:
SELECT trackId, genreId, @newRank := SUM(ranking) as ranking
FROM rankings_2016
WHERE timestamp >= ( select unix_timestamp('2016-01-01') )
AND timestamp <= ( select unix_timestamp('2016-12-31') )
GROUP BY trackId, genreId
对于艺术家:
SELECT artistId, genreId, @newRank := SUM(a1.ranking) as ranking
FROM rankings_2016 a1
LEFT JOIN artists_tracks a2
ON a1.trackId = a2.trackId
WHERE timestamp >= ( select unix_timestamp('2016-01-01') )
AND timestamp <= ( select unix_timestamp('2016-12-31') )
GROUP BY artistId, genreId
提前感谢大家的提示。
更新
一般逻辑(和接受的回复)需要良好的索引和高性能的服务器。
在我的案例中,ARTISTS 失败并出现错误 500,除非我增加 CPU。 通常用 INNER 替换 LEFT 可以节省 1 秒。
考虑一个相关的计数子查询,以按艺术家/曲目/流派分组对排名进行排序。然后在外部查询中使用此 rank 计算列过滤每个分组的前 10 个:
艺术家排名(每个艺术家和流派的前 10 名排名)
SELECT main.artistId, main.genreId, main.ranking
FROM
(
SELECT a.artistId, r.genreId, r.ranking,
(SELECT COUNT(*) FROM rankings_2016 subr
LEFT JOIN artists_tracks suba ON subr.trackId = suba.trackId
WHERE suba.artistId = a.artistId
AND subr.genreId = r.genreId
AND subr.ranking >= r.ranking) AS rn
FROM rankings_2016 r
LEFT JOIN artists_tracks a ON r.trackId = a.trackId
WHERE r.timestamp BETWEEN ( select unix_timestamp('2016-01-01') )
AND ( select unix_timestamp('2016-12-31') )
) AS main
WHERE main.rn <= 10
曲目排名(每个曲目和流派的前 10 名)
SELECT main.trackId, main.genreId, main.ranking
FROM
(
SELECT r.trackId, r.genreId, r.ranking,
(SELECT COUNT(*) FROM rankings_2016 subr
WHERE subr.genreId = r.genreId
AND subr.trackId = r.trackId
AND subr.ranking >= r.ranking) AS rn
FROM rankings_2016 r
WHERE r.timestamp BETWEEN ( select unix_timestamp('2016-01-01') )
AND ( select unix_timestamp('2016-12-31') )
) AS main
WHERE main.rn <= 10