PHP/MySQL中的秩计算
我在MySQL中有一个表,比如说它有两个字段Username、GameName和Score。 我想计算一个独立游戏名的用户排名,以便进行查询PHP/MySQL中的秩计算,php,mysql,ranking,Php,Mysql,Ranking,我在MySQL中有一个表,比如说它有两个字段Username、GameName和Score。 我想计算一个独立游戏名的用户排名,以便进行查询 SELECT * FROM scores WHERE `GameName` = 'Snake' ORDER BY `Score` DESC 按从高到低的顺序获取所有用户的列表,并为每个用户分配一个编号 但是,有没有一种更简单的方法来获取单个用户的排名,而不是选择整个表,因为这似乎效率不高 谢谢从用户表中获取用户id并在查询中使用 SELECT * FR
SELECT * FROM scores WHERE `GameName` = 'Snake' ORDER BY `Score` DESC
按从高到低的顺序获取所有用户的列表,并为每个用户分配一个编号
但是,有没有一种更简单的方法来获取单个用户的排名,而不是选择整个表,因为这似乎效率不高
谢谢从用户表中获取用户id并在查询中使用
SELECT * FROM scores WHERE `GameName` = 'Snake'
and `youruseridfield` = '$useridvalue'
ORDER BY `Score` DESC
从users表中获取用户id,并在查询中使用它
SELECT * FROM scores WHERE `GameName` = 'Snake'
and `youruseridfield` = '$useridvalue'
ORDER BY `Score` DESC
从“GameName”=“Snake”&&userID=“$userID”按“Score”DESC排序的分数中选择*从“GameName”=“Snake”&&userID=“$userID”按“Score”DESC排序的分数中选择*您应该为GameName和分数添加索引。在插入查询=>mysql\u real\u escape\u字符串之前,不要忘记转义GameName。
@布莱恩:难道不是吗?你应该给游戏名和分数添加索引。在插入查询=>mysql\u real\u escape\u字符串之前,不要忘记转义GameName。
@布莱恩:如果你想要整体排名,不幸的是你必须对整个表格进行排序。简单地说,如果不知道表中的其他等级,就无法知道某人在表中的等级 也就是说,如果您担心性能,这里有一个相当简单的解决方案-将排名查询的结果缓存到另一个MySQL表中!,并查询所有读取的数据。当有人发布新分数时,重新计算临时表。您可以定期刷新某个级别下的所有记录,例如,排名低于100的任何人都会从分数表中删除,以保持重新计算的速度,因为没有人会在被更高的分数击倒后再爬上该级别
# Create your overall leaderboards once
create table leaderboards (rank integer primary key, score_id integer, game varchar(65), user_id integer, index game_user_id_idx (game, user_id))
# To refresh your leaderboard, we'll query the ranks for the game into a temporary table, flush old records from scores, then copy
# the new ranked table into your leaderboards table.
# We'll use MySQL's CREATE TABLE...SELECT syntax to select our resultset into it directly upon creation.
create temporary table tmp_leaderboard (rank integer primary key auto_increment, score_id integer, game varchar(65), user_id integer)
select ID, GameName, UserID, from scores where GameName = '$game' order by score desc;
# Remove old rankings from the overall leaderboards, then copy the results of the temp table into it.
delete from leaderboards where game = '$game';
insert into leaderboards (rank, score_id, game, user_id)
select rank, score_id, game, user_id from tmp_leaderboard;
# And then clean up the lower scores from the Scores table
delete from scores join tmp_leaderboard on scores.id = tmp_leaderboard.score_id, scores.GameName = tmp_leaderboard.game where tmp_leaderboard.rank < 100;
# And we're done with our temp table
drop table tmp_leaderboard;
如果你想要整体排名,很遗憾你必须对整个表格进行排序。简单地说,如果不知道表中的其他等级,就无法知道某人在表中的等级 也就是说,如果您担心性能,这里有一个相当简单的解决方案-将排名查询的结果缓存到另一个MySQL表中!,并查询所有读取的数据。当有人发布新分数时,重新计算临时表。您可以定期刷新某个级别下的所有记录,例如,排名低于100的任何人都会从分数表中删除,以保持重新计算的速度,因为没有人会在被更高的分数击倒后再爬上该级别
# Create your overall leaderboards once
create table leaderboards (rank integer primary key, score_id integer, game varchar(65), user_id integer, index game_user_id_idx (game, user_id))
# To refresh your leaderboard, we'll query the ranks for the game into a temporary table, flush old records from scores, then copy
# the new ranked table into your leaderboards table.
# We'll use MySQL's CREATE TABLE...SELECT syntax to select our resultset into it directly upon creation.
create temporary table tmp_leaderboard (rank integer primary key auto_increment, score_id integer, game varchar(65), user_id integer)
select ID, GameName, UserID, from scores where GameName = '$game' order by score desc;
# Remove old rankings from the overall leaderboards, then copy the results of the temp table into it.
delete from leaderboards where game = '$game';
insert into leaderboards (rank, score_id, game, user_id)
select rank, score_id, game, user_id from tmp_leaderboard;
# And then clean up the lower scores from the Scores table
delete from scores join tmp_leaderboard on scores.id = tmp_leaderboard.score_id, scores.GameName = tmp_leaderboard.game where tmp_leaderboard.rank < 100;
# And we're done with our temp table
drop table tmp_leaderboard;
看看是否有办法在MySQL中获得排名是很有意思的,但下面是如何在PHP中实现这一点:
function getRank($user, $game, $limit=50) {
$sql = "
SELECT @rank:=@rank+1 AS Rank, User, GameName
FROM scores, (SELECT @rank:=1) AS i
WHERE `GameName` = '$game'
ORDER BY `Score` DESC
LIMIT 0, $limit
";
$result = mysql_query($sql);
while ($row = mysql_fetch_assoc($result)) {
if ($row['User'] == $user) {
return $row['Rank'];
}
}
return -1;
}
注意,我把限制放在那里,因为否则你只能得到30个结果。如果玩家没有排名,它将返回-1。看看是否有办法在MySQL中获得排名,这很有趣,但下面是如何在PHP中实现这一点:
function getRank($user, $game, $limit=50) {
$sql = "
SELECT @rank:=@rank+1 AS Rank, User, GameName
FROM scores, (SELECT @rank:=1) AS i
WHERE `GameName` = '$game'
ORDER BY `Score` DESC
LIMIT 0, $limit
";
$result = mysql_query($sql);
while ($row = mysql_fetch_assoc($result)) {
if ($row['User'] == $user) {
return $row['Rank'];
}
}
return -1;
}
注意,我把限制放在那里,因为否则你只能得到30个结果。如果播放机未分级,则返回-1。您无法避免读取表中的大量数据,但不需要将其全部拖回处理脚本:
SELECT COUNT(*)
FROM scores
WHERE `GameName` = 'Snake'
AND user=$some_user;
由于您可能希望第一个人的排名为“1”而不是“0”,因此增加结果
但是,如果您需要经常运行查询,那么维护已排序结果的物化视图是值得的。您可以从表中读取大量数据,但不需要将其一直拖回处理脚本:
SELECT COUNT(*)
FROM scores
WHERE `GameName` = 'Snake'
AND user=$some_user;
由于您可能希望第一个人的排名为“1”而不是“0”,因此增加结果
但是,如果您需要经常运行查询,那么维护排序结果的物化视图是值得的。我的一个查询解决方案:
select @rank:=@rank+1 AS Rank,L1.* from
(select @rank:=0) as L2,
(select i.*,count(*) as sum
FROM
transactions t
LEFT JOIN companies c on (c.id = t.company_id)
LEFT JOIN company_industries ci on (c.id = ci.company_id)
LEFT JOIN industries i on (ci.industry_id = i.id)
GROUP by i.name
ORDER BY sum desc ) as L1;
我的单一查询解决方案:
select @rank:=@rank+1 AS Rank,L1.* from
(select @rank:=0) as L2,
(select i.*,count(*) as sum
FROM
transactions t
LEFT JOIN companies c on (c.id = t.company_id)
LEFT JOIN company_industries ci on (c.id = ci.company_id)
LEFT JOIN industries i on (ci.industry_id = i.id)
GROUP by i.name
ORDER BY sum desc ) as L1;
以下查询使用秩函数,这也可以实现:
WITH game_rank AS(
SELECT
user_id,
gameName,
RANK() OVER (
PARTITION BY gameName
ORDER BY score DESC
) order_value_rank
FROM
scores
)
SELECT
*
FROM
game_rank
WHERE
gameName = "Snake";
以下查询使用秩函数,这也可以实现:
WITH game_rank AS(
SELECT
user_id,
gameName,
RANK() OVER (
PARTITION BY gameName
ORDER BY score DESC
) order_value_rank
FROM
scores
)
SELECT
*
FROM
game_rank
WHERE
gameName = "Snake";
确保$useridvalue已转义。不能在WHERE语句之前使用ORDER确保$useridvalue已转义。不能在WHERE语句之前使用ORDER。我的想法是,如果可以在MySQL中执行此操作,则可以使用临时表、子选择和/或使用列组别名计算行号。诀窍是让MySQL填充一个临时表/子查询,然后允许您只选择一个结果,即单个玩家的最高排名。如果没有反复试验和测试,我不知道该怎么做。请看:我确实理解您的意思,您是在所有玩家中查找用户的总体最高分数排名,而不是该玩家的最高分数,对吗?我的想法是,如果您可以在MySQL中执行此操作,则可以使用临时表、子选择和/或使用排名别名计算行数。诀窍是让MySQL填充一个临时表/子查询,然后允许您使用
只选择一个结果作为单个玩家的最高等级。如果没有反复试验和测试,我不知道该怎么做。请看:我确实理解您的意思,您在所有玩家中寻找的是用户的总体最高分数排名,而不是该玩家的最高分数,对吗?我认为&&&没有问题。我在php中使用它。在MySQL中,&&没有任何问题,它们都是有效的,并且充当对方的别名。许多人按照惯例使用MySQL,但这不是一成不变的。而且,这并不能回答问题,它只是为了加快查找本身。这更像是对原始问题的评论。我看不出&&有什么问题。我在php中使用它。在MySQL中,&&没有任何问题,它们都是有效的,并且充当对方的别名。许多人按照惯例使用MySQL,但这不是一成不变的。而且,这并不能回答问题,它只是为了加快查找本身。它更多的是作为对原始问题的评论。这不会给你一个排名,因为它只会在结果被where子句删减后排序。他想要整体排名——一个排行榜。这不会给你一个排名,因为它只会在结果被where条款删减后排序。他想要的是整体排名——一个排行榜。我知道这是可能的,但我只是不知道具体如何。这真的会比将查询限制在前100名所需的范围内并让PHP迭代更快吗?我从来都不需要临时表,所以我不确定。此外,这可能是一个存储过程,对吗?如果您保留从分数表中刷新旧分数的部分,速度可能会非常快。只要你在游戏和分数上有索引,PHP解决方案的速度可能是可以接受的,但它肯定会慢一些,因为你将重新计算排名,每次读取100行,而不是每次读取1行。这可能很容易成为一个存储过程,如果您想这样做,可以重写它以跳过“选择到临时表”步骤。此外,在上一次查询中,您使用的是排行榜而不是排行榜。我知道这是可能的,但我不知道具体如何。这真的会比将查询限制在前100名所需的范围内并让PHP迭代更快吗?我从来都不需要临时表,所以我不确定。此外,这可能是一个存储过程,对吗?如果您保留从分数表中刷新旧分数的部分,速度可能会非常快。只要你在游戏和分数上有索引,PHP解决方案的速度可能是可以接受的,但它肯定会慢一些,因为你将重新计算排名,每次读取100行,而不是每次读取1行。这可以很容易地成为一个存储过程,如果你想这样做,你可以重写它,跳过“选择到临时表”步骤。此外,在上一次查询中,你有了排行榜,而不是排行榜。这是个好主意。清洁和美丽。美丽的理念。干净漂亮。