PHP/MySQL中的秩计算

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

我在MySQL中有一个表,比如说它有两个字段Username、GameName和Score。 我想计算一个独立游戏名的用户排名,以便进行查询

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行。这可以很容易地成为一个存储过程,如果你想这样做,你可以重写它,跳过“选择到临时表”步骤。此外,在上一次查询中,你有了排行榜,而不是排行榜。这是个好主意。清洁和美丽。美丽的理念。干净漂亮。