包含以下列的表:
Player_id (primary key), Event_type(A,B,C), Points.
每个event_type
可能会多次出现1个玩家我想显示所有事件类型的DESC SUM(Points)GROUP BY player_id的整体排名,同时提出一些条件:
我徒劳无功:
SUM(points) WHERE event_type ="X"
GROUP BY Player_id ORDER BY SUM(points) LIMIT N
我一直在为这个头痛而奋斗一个星期,在包含子查询,UNION或临时表时非常困惑。我无法弄清楚如何将所有碎片放在一起......
我的梦想是让这个整体排名运行,并且能够在点击后访问每位玩家的详细分数....
对此开放给予任何帮助......谢谢!
源表的示例:
player_id ------ ------- EVENT_TYPE得分-----
--- 1 -------------------甲----------------的 5 ----------
--- 1 -------------------甲---------------的 10 ---------
--- 1 -------------------甲----------------的 5 ---------
--- 1 -------------------甲---------------- 5 ------ ---
--- 1 -------------------甲---------------- 2 ------ ---
--- 1 -------------------甲----------------的 15 ---------
--- 1 -------------------甲----------------的 10 ---------
--- 1 -------------------Ç---------------- 20 ------ ---
--- 1 -------------------乙----------------的 5 ---------
--- 1 -------------------乙---------------- 5 ------ ---
--- 1 -------------------乙----------------的 20 ---------
--- 2 -------------------甲----------------的 50 ---------
--- 2 -------------------乙----------------的 55 ---------
根据此示例的所需输出:
秩--- ------- player_id ----- overall_score
---- 1 ---------- 2 ----------- 105分 [50来自A(最佳5)+ 55来自B(最佳2)] ---------
---- 2 ---------- 1 ----------- 90分 [45来自A(最佳5)+ 20来自C(最佳3)+ 25来自B(最佳2)] ---------
答案 0 :(得分:3)
首先:您想要的功能称为sliding window
和ranking
。 Oracle使用OVER
- 关键字和rank()
- 函数实现这些功能。 MySQL不支持这些功能,因此我们必须解决这个问题。
我使用this answer创建了以下查询。如果这对你有帮助,也给他一个+1
。
SELECT
`player_id`, `event`, `points`,
(SELECT 1 + count(*)
FROM `points`
WHERE `l`.`player_id` = `player_id`
AND `l`.`event` = `event`
AND `points` > `l`.`points`
) AS `rank`
FROM
`points` `l`
这将输出player_id
的每个event
和points
的排名。例如:
假设(player_id, event, points)
有(1,A,10), (1,A,5), (1,A,2), (1,A,2), (1,A,1), (2,A,0)
,则输出为
player_id event points rank
1 A 10 1
1 A 5 2
1 A 2 3
1 A 2 3
1 A 1 5
2 A 0 1
排名不是密集的,所以如果你有重复的元组,你将得到具有相同排名的输出元组以及你的排名数的差距。
要获取每个N
和player_id
的最高event
*元组,您可以创建视图或在条件中使用子查询。视图是首选方式,但您没有权限在许多服务器上创建视图。
创建包含rank
列的视图。
CREATE VIEW `points_view`
AS SELECT
`player_id`, `event`, `points`,
(SELECT 1 + count(*)
FROM `points`
WHERE `l`.`player_id` = `player_id`
AND `l`.`event` = `event`
AND `points` > `l`.`points`
) as `rank`
FROM
`points` `l`
从视图中获取所需的前N个结果:
SELECT
`player_id`, `event`, `points`
FROM `points_view`
WHERE
`event` = 'A' AND `rank` <= 5
OR
`event` = 'B' AND `rank` <= 2
OR
`event` = 'C' AND `rank` <= 3
在条件中使用排名
SELECT
`player_id`, `event`, `points`
FROM
`points` `l`
WHERE
(SELECT 1 + count(*)
FROM `points`
WHERE `l`.`player_id` = `player_id`
AND `l`.`event` = `event`
AND `points` > `l`.`points`
) <= N
要根据您的活动进一步获得不同数量的元组,您可以
SELECT
`player_id`, `event`, `points`
FROM
`points` `l`
WHERE
`event` = 'A' AND
(SELECT 1 + count(*)
FROM `points`
WHERE `l`.`player_id` = `player_id`
AND `l`.`event` = `event`
AND `points` > `l`.`points`
) <= 5
OR
`event` = 'B' AND
(SELECT 1 + count(*)
FROM `points`
WHERE `l`.`player_id` = `player_id`
AND `l`.`event` = `event`
AND `points` > `l`.`points`
) <= 2
OR
`event` = 'C' AND
(SELECT 1 + count(*)
FROM `points`
WHERE `l`.`player_id` = `player_id`
AND `l`.`event` = `event`
AND `points` > `l`.`points`
) <= 3
我只使用你的N
的最大值为5而忽略其他事件类型的其他元组,因为MySQL没有优化这个查询,导致3个独立的从属子查询。如果性能不是问题或者您没有太多数据,请保持这种方式。
*正如我解释的那样rank
并不密集,因此使用rank <= N
获取所有元组通常会导致超过N
个元组。额外的元组是重复的。
从示例表中可以看到,简单地删除重复项是一个坏主意。如果您想要player_id = 1
和event = A
的前5个结果,则需要两个元组(1,A,2)
。他们都排名第3位。但如果你删除其中一个,你最终只会获得前4个结果(1,A,10,1)
,(1,A,5,2)
,(1,A,2,3)
,(1,A,1,5)
。
要获得密集排名,您可以使用此子查询
(SELECT count(DISTINCT `points`)
FROM `points`
WHERE `l`.`player_id` = `player_id`
AND `l`.`event` = `event`
AND `points` >= `l`.`points`
) as `dense_rank`
要小心,因为这仍然会产生重复的等级。
修改强>
要将所有活动的积分与一个积分相加,请使用GROUP BY
SELECT
`player_id`, SUM(`points`)
FROM `points_view`
WHERE
`event` = 'A' AND `rank` <= 5
OR
`event` = 'B' AND `rank` <= 2
OR
`event` = 'C' AND `rank` <= 3
GROUP BY `player_id`
ORDER BY SUM(`points`) DESC
在分区(GROUP BY
)之前,结果包含正确的最高分数,因此您可以简单地将所有分数相加。
您面临的一个重大问题是rank
和dense_rank
都不会为您提供工具,每个player_id
和event
都会获得5个元组。例如:如果有人为事件A获得1000点1分,他将获得1000分,因为所有分数都将获得rank
和dense_rank
1
。
还有ROWNUM
但是:MySQL不支持这个,所以我们必须模仿它。 ROWNUM
的问题在于它将为所有元组生成复合数字。但我们想要player_id
,event
组的复合数字。我仍然在研究这个解决方案。
<强> EDIT2 强>
使用this answer我发现这个解决方案有效:
select
player_id, sum( points )
from
(
select
player_id,
event,
points,
/* increment current_pos and reset to 0 if player_id or event changes */
@current_pos := if (@current_player = player_id AND
@current_event = event, @current_pos, 0) + 1 as position,
@current_player := player_id,
@current_event := event
from
(select
/* global variable init */
@current_player := null,
@current_event := null,
@current_pos := 0) set_pos,
points
order by
player_id,
event,
points desc
) pos
WHERE
pos.event = 'A' AND pos.position <= 5
OR
pos.event = 'B' AND pos.position <= 2
OR
pos.event = 'C' AND pos.position <= 3
GROUP BY player_id
ORDER BY SUM( points ) DESC
内部查询选择(player_id,event,points)-tuples,按player_id和event对它们进行排序,最后给每个元组一个复合数字,每当player_id或event更改时,该数字将重置为0。由于顺序,具有相同player_id的所有元组将是连续的。外部查询与先前使用的查询对视图执行的操作相同。
编辑3 (见评论)
您可以使用OLAP ROLLUP-operator创建中间总和或不同类型的分区。例如,查询将如下所示:
select
player_id, event, sum( points )
from
(
select
player_id,
event,
points,
/* increment current_pos and reset to 0 if player_id or event changes */
@current_pos := if (@current_player = player_id AND
@current_event = event, @current_pos, 0) + 1 as position,
@current_player := player_id,
@current_event := event
from
(select
/* global variable init */
@current_player := null,
@current_event := null,
@current_pos := 0) set_pos,
points
order by
player_id,
event,
points desc
) pos
WHERE
pos.event = 'A' AND pos.position <= 5
OR
pos.event = 'B' AND pos.position <= 2
OR
pos.event = 'C' AND pos.position <= 3
GROUP BY player_id, event WITH ROLLUP
/* NO ORDER BY HERE. SEE DOCUMENTATION ON MYSQL's ROLLUP FOR REASON */
结果现在首先按player_id, event
分组,然后仅按player_id
分组,最后归零(汇总所有行)。
第一组看起来像(player_id, event, sum(points)) = {(1, A, 20), (1,B,5)}
,其中20和5是关于player_id
和event
的点的总和。第二组看起来像(player_id, event, sum(points)) = {(1,NULL,25)}
。 25是关于player_id
的所有点的总和。希望有所帮助。 : - )
答案 1 :(得分:0)
你可能需要给总和(点数)一个名字。
所以:
select player,sum(points) as points from table where event_type = "x" group by player order by points desc limit 5;
(我需要看看你确切的表架构,把它写成你可以插入的东西,但这是它的要点)