【问题标题】:MySQL select subquery with sum, limit and orderMySQL选择子查询与总和,限制和顺序
【发布时间】:2017-09-03 13:48:38
【问题描述】:

我需要从所有学科的每个团队中选择前 3 名的总和。更好的分数=更多的分数。所以我可以显示比赛的一般分数。我尝试运行某事。像这样:

SELECT t.name, 
  (SELECT SUM(points) FROM (SELECT points
    FROM scores
    WHERE team = t.id
    ORDER BY points DESC
    LIMIT 3) points) sum
  FROM teams t

但我得到错误:

Unknown column 't.id' in 'where clause'

以下是架构和数据的链接: http://sqlfiddle.com/#!9/ecc66b/20

请帮助我。我确信这个查询可以在 MsSQL 中工作,但我不得不使用 MySQL

【问题讨论】:

  • 如果我没记错的话,您只能访问 1 级深的外部查询,并且您在更深的级别上使用它,因此会出现错误。

标签: mysql scope subquery sql-order-by limit


【解决方案1】:

您要做的是从外部查询的列中获取值,该列是当前查询的外部查询。

除此之外,您能否不简单地在第二个子查询中使用SUM() 函数,这样就不需要第一个子查询了。

看看你修改后的fiddle here

还可以找到更多关于该问题的信息here

【讨论】:

  • 抱歉,SUM 与我们预期的限制不兼容。数据库引擎首先将满足WHERE要求的所有结果求和,输出一行(所有元素的总和),然后将LIMIT 3应用于这一行。
  • 不敢相信我错过了那个,抱歉,这是一个糟糕的答案:-)
【解决方案2】:

在 MySQL 中选择每个组的前 3 个排名(或每个组的前 N ​​个)是一个非常棘手的问题,它没有任何内置支持像 ROW_NUMBERRANKDENSE_RANK。正如您在有关 SQL Server 的评论中可能发现的那样,这个问题在另一个支持分析函数的数据库(如 SQL Server)中会更容易处理。

MySQL 中的一个选项是使用会话变量模拟分析函数。对于您的数据集,我们可能想要模拟密集等级。考虑以下查询:

SET @dr = 0;
SET @points = NULL;
SET @team = NULL;

SELECT
    s.dr,
    s.points,
    t.name AS team_name,
    d.name AS discipline_name
FROM
(
    SELECT
        @dr:=CASE WHEN @team = team AND @points <> points THEN @dr + 1
                  WHEN @team = team AND @points = points THEN @dr
                  ELSE 1 END AS dr,
        @points:=points AS points,
        @team:=team AS team,
        discipline
    FROM scores s
    ORDER BY
        s.team,
        s.points DESC
) s
INNER JOIN teams t
    ON s.team = t.id
INNER JOIN disciplines d
    ON s.discipline = d.id
WHERE s.dr <= 3
ORDER BY
    s.team,
    s.points DESC;

输出:

请注意,在上面的输出中,狗队中的第三名在跑步和飞行学科之间并列。您的数据包含这样的关系很好,因为这是一个不值得关注的极端情况。其实这也是我选择模拟dense rank的原因,而不是行号,后者可能会任意选择两个第三名的记录之一上报。

演示在这里:

Rextester

SQLFiddle

(你原来的 Fiddle 更新了)

【讨论】:

    【解决方案3】:

    无需考虑公平分数。这是符合我预期的代码。

    SET @dr = 0;
    SET @points = NULL;
    SET @team = NULL;
    
    SELECT
        sum(s.points) points_total,
        t.name AS team_name
    FROM
    (
        SELECT
            @dr:=CASE WHEN @team = team THEN @dr + 1 ELSE 1 END AS dr,
            @points:=points AS points,
            @team:=team AS team,
            discipline
        FROM scores s
        ORDER BY
            s.team,
            s.points DESC
    ) s
    INNER JOIN teams t
        ON s.team = t.id
    INNER JOIN disciplines d
        ON s.discipline = d.id
    WHERE s.dr <= 3
    GROUP BY 
      t.name
    ORDER BY
        1 DESC;
    

    感谢@Tim Biegeleisen 显示路径。

    输出:

    【讨论】:

    • 现在我对您的要求感到困惑。 select sum of top 3 scores from each team from all disciplines 究竟是什么意思?
    • 对于一般分数,每支球队获得三个最好(多分)的结果(无论哪个学科)。所以我需要对每支队伍的分数进行DESCending排序,取其中的3个,加起来就是队伍的总成绩。
    猜你喜欢
    • 1970-01-01
    • 2014-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多