基于不同 ID 计算平均值,同时保留 table 中的所有数据?

Calculating average based on distinct ID while preserving all the data in a table?

如果我有这样的数据:

+------+----+-------+-------+
| year | id | value | group |
+------+----+-------+-------+
| 2019 |  1 |    10 | A     |
| 2019 |  1 |    10 | B     |
| 2019 |  2 |    20 | A     |
| 2019 |  3 |    30 | A     |
| 2019 |  2 |    20 | B     |
| 2020 |  1 |     5 | A     |
| 2020 |  1 |     5 | B     |
| 2020 |  2 |    10 | A     |
| 2020 |  3 |    15 | A     |
| 2020 |  2 |    10 | B     |
+------+----+-------+-------+

有没有办法在保留所有数据的同时,根据不同的 id 计算平均值 value

我需要这样做,因为我还将有 WHERE 子句来过滤 table 中的其他列,但我还需要获得数据的总体视图如果未添加 WHERE 子句(这些 WHERE 过滤器将由我无法控制的 OUTERMOST 查询中的自动化软件添加)。

group 列就是一个例子。

对于上面的例子,结果应该是:

Overall --> 20 for 2019 and 10 for 2020

WHERE group = 'A' --> 2019 年 20 个,2020 年 10 个

WHERE group = 'B' --> 2019 年为 15,2020 年为 7.5

我尝试执行以下操作:

SELECT 
  year,
  AVG(IF(id = LAG(id) OVER (ORDER BY id), NULL, value)) AS avg
FROM table
WHERE group = 'A' -- this clause may or may not exist
GROUP BY year

基本上我在想如果我按id排序并检查前一行是否有相同的id,该值应该是NULL因此它不会被计入计算,但是不幸的是,我无法将分析函数放入 aggregate 函数中。

以下查询将为您提供预期的输出。

SELECT 
  `Year`,
  AVG(DISTINCT `value`*1.0) `value`
FROM table
WHERE `group` = 'B' -- this clause is optional
GROUP BY `Year`;

查询将return以下结果。

Year | Value
2019 | 20
2020 | 10

SQLFiddle

虽然数据模型不合适且未规范化(您在冗余地存储值),但真正的问题是后期自动 SQL 注入(可选添加的 where 子句)。

当 where 子句添加到您的查询时,一切都很好,因为 where 子句正确地限制了要考虑的行(A 组或 B 组)。但是,当没有添加 where 子句时,您将不得不处理聚合数据集(不同的 year/id 行)。后者意味着聚合上的聚合,这可以通过 DineshDB 在较早的答案中显示的子查询来完成。但是这里有一个问题,where 子句必须对中间结果(子查询)起作用,而您说您的软件将 where 子句添加到主查询中。

令人惊讶的解决方案是进行这三个聚合。在下面的查询中,我混合了 MAX(第一个聚合)、AVG OVER(第二个聚合)和 DISTINCT(第三个聚合),这三个可以在一个查询中愉快地共存。不需要子查询。

SELECT DISTINCT
  year,
  AVG(MAX(value)) OVER (PARTITION BY year)
FROM yourtable
WHERE `group` = ... -- optional where clause
GROUP BY year, id
ORDER BY year;

演示:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=973ae4f260597392c55f260d3c260084