【问题标题】:MySQL: How to get user with most wins?MySQL:如何让用户获得最多胜利?
【发布时间】:2009-09-25 12:51:19
【问题描述】:

我有一个包含以下字段的表:id、opp1、opp2、opp1_votes、opp2_votes。

如果其中一个 opps 的票数比另一个多,那么我们认为他赢了。我怎样才能从这个表中获得最多胜利的 opp?

【问题讨论】:

  • 你的问题很奇怪。我们习惯于有一个像 (id, opp, opp_votes) 这样的表,然后找到最大值。为什么列重复?
  • 可能是因为他存储了 2 个相互对抗的对手。
  • 我猜是优先投票系统
  • 是的,是2个对手。对不起,我的英语很差。

标签: sql mysql select


【解决方案1】:

此查询将查找每个用户的获胜次数,并按降序排列(因此获胜次数最多的将是第一行):

SELECT winner, COUNT(*)
FROM
    (
    SELECT opp1 AS winner FROM table
    WHERE opp1_votes > opp2_votes
    UNION ALL
    SELECT opp2 AS winner FROM table
    WHERE opp2_votes > opp1_votes
    )
GROUP BY winner
ORDER BY COUNT(*) DESC

查询说明:

  1. 首先,我们找到 opp1 获胜的所有行。我们生成一个表格,其中 opp1 获胜者列在字段名称“winner”下。
  2. 我们执行与 (1) 中相同的操作,但现在针对 opp2 获胜的情况。
  3. 我们将这两个表联合起来,并获得所有游戏中所有获胜者的列表。
  4. 现在,我们按获胜者 ID 对结果表进行分组,并从该分组中选择计数,从而生成一个获胜者列表,以及每个获胜者的获胜次数。
  5. 最后一步是按获胜次数降序排列。

注意事项:

  • 根据上面的查询,如果出现平局 - 没有赢家。如果您想将平局视为其中一位用户的胜利,则需要定义打破平局的启发式方法。
  • 如果你真的只想要一个结果,你可以从SELECT TOP 1 winner, ... 开始或以LIMIT 1 结束,但据我所知,在一般情况下它不会节省计算时间,所以我会留下它。

【讨论】:

  • 您的“ORDER BY”子句缺少“BY”字样;)
  • 当 opp 作为 opp1 和 opp2 获胜时,UNION 在过滤重复项时会删除它。我认为你应该放一个'UNION ALL'
  • 我在每个获胜者的 COUNT(*) 列中得到“1”
  • @Konstantin:你在我重构的答案中使用了 UNION ALL 吗?您可能使用了以前的 UNION(再次感谢 najmeddine)
  • 你说得对,我没注意到。非常感谢您,您的解决方案完美运行。
【解决方案2】:
SELECT opp, sum(win) wins FROM ( 
    SELECT opp1 opp, CASE WHEN opp1_votes > opp2_votes THEN 1 ELSE 0 END win
      FROM otable
    UNION ALL
    SELECT opp2 opp, CASE WHEN opp2_votes > opp1_votes THEN 1 ELSE 0 END win
      FROM otable
) A
GROUP BY opp
ORDER BY sum(win) DESC LIMIT 1

【讨论】:

  • 不确定这对于特定的数据库是否可行,但如果同一对手出现在某些行的 opp1 和其他行的 opp2 中,这种方法可能会失败。
  • 我认为您的 SUM 行有括号问题。
  • @jbourque - 很好,您只想确保对于每一行,您要么在第一种情况下(opp1 获胜)或第二种情况下(opp2 获胜)返回它。在 UNION 之后,您将无法判断获胜者的位置。
  • 我做了一些重构。谢谢。
【解决方案3】:
SELECT
    CASE WHEN opp1_votes > opp2_votes THEN opp1 ELSE opp2 END as winner,
    COUNT(*)
FROM table
GROUP BY CASE WHEN opp1_votes > opp2_votes THEN opp1 ELSE opp2 END
ORDER BY COUNT(*) DESC

【讨论】:

    【解决方案4】:

    这个小查询将为您提供所有获胜者以及他获胜的次数(按降序排列):

    SELECT
    (CASE WHEN `opp1_votes`>`opp2_votes` THEN `opp1` ELSE `opp2` END) `winner`,
    COUNT(*) AS `no_of_times`
    FROM `matches`
    GROUP BY `winner`
    ORDER BY `no_of_times` DESC
    

    我们在这里做的是:

    1. 比较 CASE WHEN 子句中的 opp1_votes 和 opp2_votes 中哪个更大
    2. 如果 opp1_votes 更高,则我们在 winner 列中输出 opp1,反之亦然
    3. 然后我们将结果按获胜者分组
    4. 现在,如果计算每个获胜者的行数,我们会得到每个获胜者的获胜次数
    5. 结果按 no_of_times won 排序

    如果您只想要获胜次数最多的人,您可以将LIMIT 1 添加到查询的末尾,或者您可以包装上述查询并从中选择 max(no_of_times),如下所示:

    SELECT `winner`, MAX(`no_of_times`) AS `no_of_times` FROM (
    SELECT
    (CASE WHEN `opp1_votes`>`opp2_votes` THEN `opp1` ELSE `opp2` END) `winner`,
    COUNT(*) AS `no_of_times`
    FROM `matches`
    GROUP BY `winner`
    ORDER BY `no_of_times` DESC
    ) AS `winners`
    

    【讨论】:

    • 是的,但这会更快,但我猜这并不总是重要的。好吧,无论如何我都喜欢回答这个问题,所以不用担心
    【解决方案5】:

    这是你想要的吗?

    select top 1 opp1, 
       (select count(*) 
          from table i 
          where i.opp1 = o.opp1 and i.opp1votes > i.opp2votes) as wins 
    from table o 
    order desc by wins
    

    【讨论】:

    • 没有必要检查 opp2 因为我假设表中的其他地方有一个镜像条目,对吧?否则我不完全理解你的数据集
    • 不,它是这样工作的:有人开始战斗,他被视为 opp1,然后有人加入他,第二个被视为 opp2。但是每个人都可以开始或加入战斗,所以一个人在不同情况下可以是opp1或opp2。
    • 啊,好的。现在我了解更多......然后我认为其他人已经有了解决方案。我不会再发帖了;)我以为每场比赛都有两个条目。一个玩家是 opp1,另一个从另一个角度来看他/她是 opp2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多