6

我这里有一个问题,我希望有一个简单的解决方案。我会尽量简化:

  • 票属于参加者
  • 例子:

select * from tickets JOIN attendees ON attendee.id = tickets.attendee_id
  • 与会者有一个名为“收入”的小数列

也就是说,我需要运行一个查询,该查询将返回有关门票的各种信息,包括总收入。问题是,如果 2 张门票属于同一个与会者,则会将他们的收入计算两次。我怎样才能只对与会者收入进行一次汇总?

我不想使用子查询,因为我的 ORM 让这很困难。另外,如果我想对多列执行此操作,则子查询解决方案无法扩展。

这是我所拥有的:

  • 1 名与会者收入为 100
  • 2 张都属于该与会者的门票

Select count(tickets.*) as tickets_count
     , sum(attendees.revenue) as atendees_revenue
from tickets LEFT OUTER JOIN attendees ON attendees.id = tickets.attendee_id;

=> 这告诉我attendees_revenue是 200。我希望它是 100。因为数据库中有一个出席者的 existing_revenue 为 100。我不希望出席者被重复计算。

请让我知道这是否可能。

4

4 回答 4

8

要在没有 subquery的情况下获得结果,您必须使用高级窗口函数技巧:

SELECT sum(count(*))       OVER () AS tickets_count
     , sum(min(a.revenue)) OVER () AS atendees_revenue
FROM   tickets   t
JOIN   attendees a ON a.id = t.attendee_id
GROUP  BY t.attendee_id
LIMIT  1;

sqlfiddle

它是如何工作的?

理解这一点的关键是查询中的事件顺序

聚合函数 -> 窗口函数 -> DISTINCT -> LIMIT

更多细节:

一步步:

  1. I GROUP BY t.attendee_id- 您通常会在子查询中执行此操作。

  2. 然后我将计数相加以获得票的总数。效率不高,但受您的要求所迫。聚合函数count(*)被包装在窗口函数sum( ... ) OVER ()中以得到不常见的表达式:sum(count(*)) OVER ()

    并将每位与会者的最低收入相加,以获得不重复的总和。

    您也可以使用max()oravg()代替,min()revenue保证每个与会者的每一行都相同的效果。

    DISTINCT如果在窗口函数中允许,这可能会更简单,但 PostgreSQL 还没有(还)实现这个特性。根据文档

    聚合窗口函数与普通聚合函数不同,不允许DISTINCTORDER BY在函数参数列表中使用。

  3. 最后一步是获得单行。这可以使用DISTINCT(SQL 标准)来完成,因为所有行都是相同的。LIMIT 1不过会更快。或 SQL 标准形式FETCH FIRST 1 ROWS ONLY

于 2012-11-01T01:05:30.243 回答
3

一个简单的划分呢:

 Select count(tickets.*) as tickets_count
 , sum(attendees.revenue) / count(attendees.id) as atendees_revenue
 from tickets LEFT OUTER JOIN attendees ON attendees.id = 
 tickets.attendee_id;

这应该处理重复、三次等。

于 2017-11-20T23:03:36.327 回答
-1

以前的答案几乎是正确的。如果收入相同,您只需要做好不同的工作。如果您的 id 具有数字类型,您可以非常简单地解决这个问题:

SELECT
  COUNT(*) AS ticketsCount,
  SUM(DISTINCT attendees.id + attendees.revenue) - SUM(DISTINCT attendees.id) AS revenueSum
FROM
  tickets
LEFT JOIN attendees ON
  attendees.id = tickets.attendee_id
于 2017-08-26T21:14:28.783 回答
-3

您实际上非常接近,有很多方法可以做到这一点,如果我正确理解您的问题,应该这样做:

SELECT
   COUNT(*) AS ticketsCount,
   SUM(DISTINCT attendees.revenue) AS revenueSum
FROM
   tickets
   LEFT JOIN attendees ON
      attendees.id = tickets.attendee_id
于 2012-11-01T00:56:57.700 回答