За да получите резултата без подзаявка , трябва да прибягвате до измама с разширени функции на прозореца:
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
Повече подробности:
- Най-добрият начин да получите резултат, преди да бъде приложен LIMIT
Стъпка по стъпка:
-
I
GROUP BY t.attendee_id
- което обикновено правите в подзаявка. -
След това сумирам преброяванията, за да получа общия брой на билетите. Не е много ефективно, но принудено от вашето изискване. Агрегатната функция
count(*)
е обвит във функцията на прозорецаsum( ... ) OVER ()
за да стигнем до не толкова често срещания израз:sum(count(*)) OVER ()
.И сумирайте минималните приходи на присъстващ, за да получите сумата без дубликати.
Можете също да използвате
max()
илиavg()
вместоmin()
със същия ефект катоrevenue
е гарантирано, че е една и съща за всеки ред на присъстващ.Това може да бъде по-лесно, ако
DISTINCT
беше разрешено във функциите на прозореца, но PostgreSQL (все още) не е внедрил тази функция. По документация:Функциите на прозореца за обобщени, за разлика от нормалните агрегатни функции, не позволяват
DISTINCT
илиORDER BY
да се използва в списъка с аргументи на функцията. -
Последната стъпка е да получите един ред. Това може да стане с
DISTINCT
(SQL стандарт), тъй като всички редове са еднакви.LIMIT 1
все пак ще е по-бързо. Или стандартния SQL формулярFETCH FIRST 1 ROWS ONLY
.