使用复杂查询对系统进行排名:更精确的过滤器

时间:2012-10-19 14:15:16

标签: mysql sql subquery ranking

为了在我的游戏服务器上实现排名系统,我将每个玩家的一些信息存储在MySQL数据库中。 我有以下数据库表。

带有示例数据的表players

id | steamId | deaths
---+---------+-------
1  | asdja   | 2
2  | kfjsl   | 5

带有示例数据的表weapons

playerId | weaponId | kills
---------+----------+------
1        | 5        | 8
1        | 9        | 7
2        | 3        | 3
2        | 6        | 10
2        | 7        | 2

你知道我没有在players - 表中存储每个玩家的杀戮,因为我可以从weapons - 表中简单地计算出来。 我对SQL查询不是很熟悉,但是我完成了以下创建,以便选择一个包含以下字段的简单数据集:

kills,
deaths,
kill-death-rate (kdrate),
count (maximum number of players),
rank (current ranking position, sorted by kills)

查询:

SELECT
    SUM(weapons.kills) AS `kills`,
    `deaths`,
    (SUM(kills) / IF(deaths, deaths, 1)) AS `kdrate`,
    (SELECT COUNT(*) FROM `players`) AS `count`,
    (
        SELECT
            COUNT(*)
        FROM
            (
                SELECT
                    p.id AS id2,
                    SUM(w.kills) AS kills2,
                    p.deaths AS deaths2,
                    p.steamId AS steamId2
                FROM
                    weapons AS w,
                    players AS p
                WHERE
                    p.id = w.playerId
                GROUP BY
                    p.id
            ) AS temp
        WHERE
            temp.kills2 >= (
                SELECT
                    SUM(weapons.kills) AS `kills`
                FROM
                    `players`,
                    `weapons`
                WHERE
                    players.id = weapons.playerId AND
                    `id` = 1
                GROUP BY
                  `id`
            )
        ORDER BY
            temp.kills2 DESC,
            temp.deaths2 ASC,
            temp.steamId2 ASC
    ) AS `rank`
FROM
    `players`
INNER JOIN
    `weapons`
ON
    players.id = weapons.playerId
WHERE
    `id` = 1
GROUP BY
    `id`

有两个问题:

1。)查询太可怕了。

2。)使用给定的示例数据执行此查询会产生“相同的等级”。 我的意思是,两名球员都获得相同的排名,因为我对两名球员的杀人数量是相同的。 但相反,玩家1应该在等级1,因为他的死亡人数少于玩家2。 我不知道怎么能意识到这一点。

提前致谢!

编辑: @Manueru_mx给了我一个如何做的基本想法: 我根据他的回答得到了以下代码:

SELECT
    id,
    kills,
    deaths,
    kdrate,
    COUNT(*) AS rank,
    (SELECT COUNT(*) FROM players) AS `count`
FROM
    (
        SELECT
            pys.id AS id,
            SUM(wps.kills) AS kills,
            pys.deaths AS deaths,
            (SUM(wps.kills) / pys.deaths) as kdrate
        FROM
            players pys
        INNER JOIN
            weapons wps
        ON
            pys.id = wps.playerid
        GROUP BY
            pys.id
        ORDER BY
            2 DESC,
            3,
            4 ASC
    ) AS tmp
WHERE
    id = 1

唯一的问题是,rank在两种情况下均为1。

3 个答案:

答案 0 :(得分:2)

这是我的“解决方案”。此查询更简单但获得您正在查看的结果

select 
pys.steamID, SUM(wps.kills) as Kills,
SUM(pys.deaths) as Deaths,
(sum(wps.kills)/sum(pys.deaths)) as kdratio
--,COUNT(pys.steamID) as PlayersC
from players pys
inner join  weapons wps on pys.id = wps.playerid
group by pys.steamID
order by 2 DESC, 3, 4 ASC

添加排名。

SELECT
    id,
    kills,
    deaths,
    kdrate,
    ranking_usr as rank,
    (SELECT COUNT(*) FROM players) AS `count`
FROM
    (
        SELECT
            @row := @row + 1 AS ranking_usr
            pys.id AS id,
            SUM(wps.kills) AS kills,
            pys.deaths AS deaths,
            (SUM(wps.kills) / pys.deaths) as kdrate
        FROM
            players pys
        INNER JOIN
            weapons wps
        ON
            pys.id = wps.playerid
        GROUP BY
            pys.id
        ORDER BY
            2 DESC,
            3,
            4 ASC
    ) AS tmp
WHERE
    id = 1

答案 1 :(得分:2)

基于Manueru_mx答案,这是解决方案:

SELECT
    *
FROM
    (
    SELECT
        id,
        kills,
        deaths,
        kdrate,
        @rownum := @rownum + 1 AS rank,
        (SELECT COUNT(*) FROM players) AS `count`
    FROM
        (
            SELECT
                pys.id AS id,
                SUM(wps.kills) AS kills,
                pys.deaths AS deaths,
                (SUM(wps.kills) / pys.deaths) as kdrate
            FROM
                players pys
            INNER JOIN
                weapons wps
            ON
                pys.id = wps.playerid
            GROUP BY
                pys.id
            ORDER BY
                2 DESC,
                3,
                4 ASC
        ) AS tmp,
        (SELECT @rownum:= 0) r
    ) AS tmp2
WHERE
    id = 1

答案 2 :(得分:0)

您期望的结果是什么? 你可以通过运行来简单地知道播放了多少次杀戮:

select id, (select sum (kills) from weapons where playerid = p.id)
from  players p