基于不同 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
虽然数据模型不合适且未规范化(您在冗余地存储值),但真正的问题是后期自动 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
如果我有这样的数据:
+------+----+-------+-------+
| 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
虽然数据模型不合适且未规范化(您在冗余地存储值),但真正的问题是后期自动 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