GROUP BY 一列,然后 GROUP BY 另一列

GROUP BY one column, then GROUP BY another column

我有一个数据库 table t 的销售额 table:

ID 类型 年龄
1 B 20
1 BP 20
1 BP 20
1 P 20
2 B 30
2 BP 30
2 BP 30
3 P 40

如果有人购买捆绑包,则会显示捆绑销售 (TYPE B) 和不同的捆绑产品 (TYPE BP),它们都具有相同的 ID。因此,包含 2 个产品的捆绑包出现了 3 次(1x TYPE B 和 2x TYPE BP)并且具有相同的 ID。

一个人还可以购买该单次销售 (TYPE P) 中的任何其他产品,该产品也具有相同的 ID。

我需要计算客户的 average/min/max 年龄,但每次销售的多个条目会影响正确的计算。

真实平均年龄是

(20 + 30 + 40) / 3 = 30

而不是

(20+20+20+20 + 30+30+30 + 40) / 8 = 26,25

但我不知道如何将销售额减少到单行条目并获得所需的 4 个值?

我是否需要 GROUP BY 两次(首先按 ID,然后按年龄?)如果是,我该怎么做?

到目前为止我的代码:

SELECT
      AVERAGE(AGE)
    , MIN(AGE)
    , MAX(AGE)
    , MEDIAN(AGE)
FROM t

但这确实计算每一行。

假设具有相同 ID 的所有行的年龄都相同(这本身表明存在规范化问题),您可以使用 nest aggregation:

select avg(min(age)) from sales
group by id
AVG(MIN(AGE))
-------------
           30

SQL Fiddle

文档中的示例非常相似;并解释为:

This calculation evaluates the inner aggregate (MAX(salary)) for each group defined by the GROUP BY clause (department_id), and aggregates the results again.

因此对于您的版本:

此计算计算 GROUP BY 子句 (id) 定义的每个组的内部聚合 (MIN(age)),并再次聚合结果。

内部聚合是最小值还是最大值并不重要 - 同样,假设它们都相同 - 它只是为每个 ID 获取一个值,然后可以对其进行平均。


您可以对原始查询中的其他值执行相同的操作:

select
  avg(min(age)) as avg_age,
  min(min(age)) as min_age,
  max(min(age)) as max_age,
  median(min(age)) as med_age
from sales
group by id;
AVG_AGE MIN_AGE MAX_AGE MED_AGE
------- ------- ------- -------
     30      20      40      30

或者,如果您愿意,您可以在 CTE 或子查询中获取每个 ID 一个年龄的值,并将第二层聚合应用于该值:

select 
  avg(age) as avg_age,
  min(age) as min_age,
  max(age) as max_age,
  median(age) as med_age
from (
   select min(age) as age
   from sales
   group by id
);

得到相同的结果。

SQL Fiddle