Om het resultaat te krijgen zonder subquery , moet je je toevlucht nemen tot geavanceerde bedrog van de vensterfunctie:
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
Hoe werkt het?
De sleutel om dit te begrijpen is de volgorde van gebeurtenissen in de vraag:
geaggregeerde functies -> vensterfuncties -> DISTINCT -> LIMIT
Meer details:
- De beste manier om het aantal resultaten te krijgen voordat LIMIT werd toegepast
Stap voor stap:
-
I
GROUP BY t.attendee_id
- wat u normaal gesproken zou doen in een subquery. -
Vervolgens tel ik de tellingen op om het totale aantal tickets te krijgen. Niet erg efficiënt, maar gedwongen door uw vereiste. De aggregatiefunctie
count(*)
is verpakt in de vensterfunctiesum( ... ) OVER ()
om tot de niet zo gebruikelijke uitdrukking te komen:sum(count(*)) OVER ()
.En tel de minimale opbrengst per deelnemer op om de som te krijgen zonder duplicaten.
Je zou ook
max()
. kunnen gebruiken ofavg()
in plaats vanmin()
met hetzelfde effect alsrevenue
is gegarandeerd hetzelfde voor elke rij per deelnemer.Dit zou eenvoudiger kunnen zijn als
DISTINCT
was toegestaan in vensterfuncties, maar PostgreSQL heeft deze functie (nog) niet geïmplementeerd. Per documentatie:Geaggregeerde vensterfuncties, in tegenstelling tot normale aggregatiefuncties, staan
DISTINCT
niet toe ofORDER BY
te gebruiken in de lijst met functieargumenten. -
De laatste stap is om een enkele rij te krijgen. Dit kan met
DISTINCT
(SQL-standaard) omdat alle rijen hetzelfde zijn.LIMIT 1
zal wel sneller zijn. Of de SQL-standaardvormFETCH FIRST 1 ROWS ONLY
.