For at få resultatet uden underforespørgsel , skal du ty til avanceret vinduesfunktionstrickeri:
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
Hvordan fungerer det?
Nøglen til at forstå dette er rækkefølgen af begivenheder i forespørgslen:
aggregerede funktioner -> vinduesfunktioner -> DISTINCT -> LIMIT
Flere detaljer:
- Bedste måde at få resultattælling, før LIMIT blev anvendt
Trin for trin:
-
Jeg
GROUP BY t.attendee_id
- hvilket du normalt ville gøre i en underforespørgsel. -
Så summerer jeg optællingerne for at få det samlede antal billetter. Ikke særlig effektiv, men tvunget af dit krav. Den samlede funktion
count(*)
er pakket ind i vinduesfunktionensum( ... ) OVER ()
for at nå frem til det ikke så almindelige udtryk:sum(count(*)) OVER ()
.Og summer minimumsindtægten pr. deltager for at få summen uden dubletter.
Du kan også bruge
max()
elleravg()
i stedet formin()
til samme effekt somrevenue
er garanteret den samme for hver række pr. deltager.Dette kunne være enklere, hvis
DISTINCT
var tilladt i vinduesfunktioner, men PostgreSQL har (endnu) ikke implementeret denne funktion. Per dokumentation:Aggregerede vinduesfunktioner tillader i modsætning til normale aggregerede funktioner ikke
DISTINCT
ellerORDER BY
skal bruges i funktionsargumentlisten. -
Sidste trin er at få en enkelt række. Dette kunne gøres med
DISTINCT
(SQL-standard), da alle rækker er ens.LIMIT 1
vil dog være hurtigere. Eller SQL-standardformenFETCH FIRST 1 ROWS ONLY
.