【问题标题】:How to take average of two columns row by row in SQL?如何在 SQL 中逐行取两列的平均值?
【发布时间】:2020-12-13 00:49:42
【问题描述】:

我有一张桌子match,看起来像这样(请参阅附图)。我想使用此代码检索具有home_goalaway_goal 平均值列的数据集

SELECT 
    m.country_id, 
    m.season,
    m.home_goal,
    m.away_goal,
    AVG(m.home_goal + m.away_goal)  AS avg_goal
FROM match AS m;

但是,我收到了这个错误

column "m.country_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 3:  m.country_id,

我的问题是:为什么需要GROUP BY 子句?为什么 SQL 不知道如何逐行取两列的平均值?

谢谢。

【问题讨论】:

  • 用您正在使用的数据库标记您的问题。

标签: sql average aggregate-functions


【解决方案1】:

试试这个:

SELECT 
    m.country_id, 
    m.season,
    m.home_goal,
    m.away_goal,
    (m.home_goal + m.away_goal)/2  AS avg_goal
FROM match AS m;

您被要求使用 group_by,因为 avg() 很像 sum() 处理一列的多个值,您可以对 group by 中所有非列明智操作的列进行分类

您希望平均两个不同的列 - 它是逐行操作而不是逐列操作

【讨论】:

  • 谢谢,DPH。现在我明白了原因。澄清一下:sumavg 等内置函数适用于按列,否则如果想按行应用,则必须使用 group by
  • @Nemo 如果您想跨列(水平)进行操作,请考虑一个公式(a + b 等)。在按列工作时,您使用 GROUP BY 来识别组成您想要计算的组(子组等)的变量(sum()、avg() 等)。当您在按列操作中通知列时(sum()、avg() 等)没有函数时,SQL 需要显式信息进行分组,因为数据集正在通过按列操作垂直压缩(意思是没有操作的值不会被压缩,现在 SQL 丢失了,因为其他的被压缩了)
  • 感谢您的澄清。我没想到在发布问题时会学到这么多。
【解决方案2】:

如何逐行取两列的平均值?

您不要为此使用AVG();它是一个聚合函数,对一组行进行操作。在这里,您似乎只需要一个简单的数学计算:

SELECT 
    m.country_id, 
    m.season,
    m.home_goal,
    m.away_goal,
    (m.home_goal + m.away_goal) / 2.0 AS avg_goal
FROM match AS m;

注意小数分母 (2.0):这避免了实现它的数据库中的整数除法。

【讨论】:

  • 感谢您的解决方案,GMB。但是为什么我不能使用AVG 函数呢?您能否在回答中详细说明,以便我接受它作为解决方案?
  • @Nemo:不,这不是AVG() 所做的。您想做的简单计算没有内置函数..
  • 你的意思是函数AVGSUM等不能在行级别使用,只能在聚合级别使用?
  • SQL 喜欢列,所以这通常是内置函数的目标。您可以使用 SQL 做任何您想做的事情,但这并不意味着它会高效或易于实施。
  • 谢谢,马克。您的评论帮助我更多地了解了 SQL 机制。
【解决方案3】:

在上述函数的上下文中,Avg 是计算列值的平均值,而不是同一行中两个值的平均值。它是一个聚合函数,这就是需要 group by 子句的原因。

为了取同一行中两列的平均值,您需要除以 2。

【讨论】:

    【解决方案4】:

    让我们考虑下表:

    CREATE TABLE Numbers([x] int, [y] int, [category] nvarchar(10));
    
    INSERT INTO Numbers ([x], [y], [category])
    VALUES
        (1, 11, 'odd'),
        (2, 22, 'even'),
        (3, 33, 'odd'),
        (4, 44, 'even');
    

    下面是使用两个聚合函数的示例 - AVG 和 SUM - 与 GROUP BY:

    SELECT
      Category,
      AVG(x) as avg_x,
      AVG(x+y) as avg_xy,
      SUM(x) as sum_x,
      SUM(x+y) as sum_xy
    FROM Numbers
    GROUP BY Category
      
    

    结果有两行:

    Category    avg_x   avg_xy  sum_x   sum_xy
    even    3   36  6   72
    odd     2   24  4   48
    

    请注意 Category 在 SELECT 部分中可用,因为结果是由它进行 GROUP BY 的。如果未指定 GROUP BY,则结果将为 1 行,Category 不可用(如果我们有不同类别的多行的总和和平均值,应该显示哪个值?)。

    你想要的是计算一个新列,为此你不使用聚合函数:

    SELECT
      (x+y)/2 as avg_xy,
      (x+y) as sum_xy
    FROM Numbers
    

    这将返回所有行:

    avg_xy  sum_xy
    6   12
    12  24
    18  36
    24  48
    

    如果您的列是整数,请不要忘记处理舍入(如果需要)。例如(CAST(x AS DECIMAL)+y)/2 as avg_xy,

    【讨论】:

      【解决方案5】:

      简单的算术计算:

      (m.home_goal + m.away_goal) / 2.0
      

      不完全等同于AVG(),因为NULL 值搞砸了。支持横向连接的数据库提供了一种在一行中实际使用AVG() 的非常简单(且高效)的方式。

      安全版本如下:

      (coalesce(m.home_goal, 0) + coalesce(m.away_goal, 0)) /
      nullif( (case when m.home_goal is not null then 1 else 0 end +
               case when m.away_goal is not null then 1 else 0 end
              ), 0
            )
      

      一些数据库具有允许简化表达式的语法扩展。

      【讨论】:

      • 感谢 Gordon 提出的新概念(coalescenullif)。你说的一些数据库是什么意思,比如层次、关系、图形、网络等?
      • @Nemo 。 . .不会。传统的关系数据库都以一种或另一种方式扩展了标准——或者支持标准的“不常见”特性。例如,Postgers 支持filter,MySQL 将布尔值视为整数。
      猜你喜欢
      • 2021-11-28
      • 2015-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-14
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多