加入后聚合,不重复

Posted

技术标签:

【中文标题】加入后聚合,不重复【英文标题】:Aggregate after join without duplicates 【发布时间】:2015-01-04 03:50:54 【问题描述】:

考虑这个查询:

select
   count(p.id),
   count(s.id),
   sum(s.price)
from 
   (select * from orders where <condition>)   as s,
   (select * from products where <condition>) as p
where 
   s.id = p.order;

例如,产品中有 200 条记录,订单中有 100 条记录(一个订单可以包含一个或多个产品)。

我需要加入然后然后:

    计数产品(应返回 200) 计数订单(应返回 100) 按订单字段之一求和(应返回按 100 个价格计算的总和)

问题是加入后 ps 长度相同,对于 2) 我可以写 count(distinct s. id),但是对于 3) 我得到了重复(例如,如果销售有 2 个产品,它会将价格加起来两次)所以 sum 适用于整个 200 条记录集,但应该只查询100.

有什么想法如何总结连接表中的不同记录而不破坏另一个选择?

例如,连接表有

id sale price
0  0    4
0  0    4
1  1    3
2  2    4
2  2    4
2  2    4

所以 sum(s.price) 将返回:

4+4+3+4+4+4=23

但我需要:

4+3+4=11

【问题讨论】:

如果您添加示例数据和预期输出,它会更加清晰 为什么“产品”表中会有order id? @Gordon Linoff:这正是我的想法。令人困惑。 抱歉,解释不清楚。当然,这个示例被简化了很多,两个表中还有很多其他字段。我不想增加问题的开销。由于@ManyToOne 关系,产品引用了订单。 【参考方案1】:

您的主要问题是桌子设计。如果没有销售,您目前无法知道产品的价格。价格应在产品表中。一种产品需要一定的价格。然后您可以统计一次销售的所有产品,并获得销售的总价格。

还有你为什么要使用子查询。当您这样做时,在连接两个子查询时将不使用任何索引。如果您的连接是那么复杂的使用视图。在大多数数据库中,它们可以被索引

【讨论】:

我在两个表中都使用了索引。这些表仅用于示例(生产中的更多字段)。很抱歉造成混乱。【参考方案2】:

您对单个产品记录不感兴趣,而只对它们的数量感兴趣。所以加入聚合(每个订单一条记录)而不是单行:

select
  count(*) as count_orders,
  sum(p.cnt) as count_products,
  sum(s.price)
from orders as s
join 
(
  select order, count(*) as cnt 
  from products 
  where <condition> 
  group by order
) as p on p.order = s.id
where <condition>;

【讨论】:

出于性能考虑,我需要先做一个过滤器(两个表都有 40kk+ 条记录)。还是谢谢。 什么?通过聚合产品,我加入了 less 记录,因此有一个 smaller 中间结果。因此,dbms 应该更快 这样做。如果没有,我会把这归咎于 postgres。对于给定的任务,编写的查询应该尽可能快。【参考方案3】:

如果products 表实际上更像是一个“订单行”表,那么查询就有意义了。您可以通过多种方式做您想做的事。这里我要建议条件聚合:

select count(distinct p.id), count(distinct s.id),
       sum(case when seqnum = 1 then s.price end)
from (select o.* from orders o where <condition>) s join
     (select p.*, row_number() over (partition by p.order order by p.order) as seqnum
      from products p
     where <condition>
     ) p
     on s.id = p.order;

通常,名为“products”的表中每个产品会有一行,其中包含描述和名称等内容。名为“OrderLines”或“OrderProducts”或“OrderDetails”的表格将包含给定订单中的产品。

【讨论】:

它就像一个魅力。我需要在“窗口功能”上浪费一些时间……看来这是值得的。谢谢!

以上是关于加入后聚合,不重复的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:加入表并根据另一列上的聚合函数从一行返回一列[重复]

聚合初始化不支持构造函数访问[重复]

聚合而不减少数据框的维度[重复]

聚合物重复模板问题

列的原因在选择列表中无效,因为它不包含在聚合函数或 GROUP BY 子句中[重复]

列在选择列表中无效,因为它不包含在聚合函数或 GROUP BY 子句中。[ntext] [重复]