我有一个问题,我希望有一个简单的解决方案。我会尝试尽可能简单:
select * from tickets JOIN attendees ON attendee.id = tickets.attendee_id
那就是说,我需要运行一个查询,返回有关门票的各种信息,包括总收入。问题是,如果2张门票属于同一位与会者,则会将其收入计入两次。如何仅将与会者收入相加一次?
我不想使用子查询,因为我的ORM使这很困难。如果我想为多列执行此操作,则子查询解决方案无法扩展。
这就是我所拥有的:
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.因为数据库中有一个参与者,其现有的回报为100.我不希望参与者被重复计算。
如果可能,请告诉我。
答案 0 :(得分:7)
要获得结果不带子查询,您必须使用高级窗口函数技巧:
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;
理解这一点的关键是查询中的事件序列:
汇总功能 - >窗口函数 - > DISTINCT - > LIMIT
此处有更多详情:
一步一步:
我GROUP BY t.attendee_id
- 您通常会在子查询中执行此操作。
然后我总结了计数以获得门票的总数。效率不高,但受到您的要求的限制。聚合函数count(*)
包含在窗口函数sum( ... ) OVER ()
中,以得到不常见的表达式:sum(count(*)) OVER ()
。
并将每位与会者的最低收入相加,以获得没有重复的金额。
您也可以使用max()
或avg()
代替min()
,效果与revenue
相同,每位与会者每行保证相同。
如果在窗口函数中允许DISTINCT
,这可能会更简单,但PostgreSQL尚未实现此功能。 Per documentation:
与普通聚合函数不同,聚合窗口函数不会 允许在函数参数列表中使用
DISTINCT
或ORDER BY
。
最后一步是获得一行。这可以使用DISTINCT
(SQL标准)来完成,因为所有行都是相同的。不过,LIMIT 1
会更快。或者SQL标准格式FETCH FIRST 1 ROWS ONLY
。
答案 1 :(得分: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;
这应该处理重复,重复,等等。
答案 2 :(得分:0)
你实际上非常接近,有很多方法可以做到这一点,如果我理解你的问题,这应该做到:
SELECT
COUNT(*) AS ticketsCount,
SUM(DISTINCT attendees.revenue) AS revenueSum
FROM
tickets
LEFT JOIN attendees ON
attendees.id = tickets.attendee_id
答案 3 :(得分:0)
以前的答案几乎是正确的。你只需要在相同的收入情况下做好明显的工作。如果你的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