@@ -361,39 +361,90 @@ DELETE FROM classname;
361361 Like most other query languages,
362362 <ProductName>PostgreSQL</ProductName> supports
363363 aggregate functions.
364- The current implementation of
365- <ProductName>Postgres</ProductName> aggregate functions have some limitations.
366- Specifically, while there are aggregates to compute
367- such functions as the <Function>count</Function>, <Function>sum</Function>,
364+ An aggregate function computes a single result from multiple input rows.
365+ For example, there are aggregates to compute the
366+ <Function>count</Function>, <Function>sum</Function>,
368367 <Function>avg</Function> (average), <Function>max</Function> (maximum) and
369- <Function>min</Function> (minimum) over a set of instances, aggregates can only
370- appear in the target list of a query and not directly in the
371- qualification (the where clause). As an example,
368+ <Function>min</Function> (minimum) over a set of instances.
369+ </para>
370+
371+ <Para>
372+ It is important to understand the interaction between aggregates and
373+ SQL's <Command>where</Command> and <Command>having</Command> clauses.
374+ The fundamental difference between <Command>where</Command> and
375+ <Command>having</Command> is this: <Command>where</Command> selects
376+ input rows before groups and aggregates are computed (thus, it controls
377+ which rows go into the aggregate computation), whereas
378+ <Command>having</Command> selects group rows after groups and
379+ aggregates are computed. Thus, the
380+ <Command>where</Command> clause may not contain aggregate functions;
381+ it makes no sense to try to use an aggregate to determine which rows
382+ will be inputs to the aggregates. On the other hand,
383+ <Command>having</Command> clauses always contain aggregate functions.
384+ (Strictly speaking, you are allowed to write a <Command>having</Command>
385+ clause that doesn't use aggregates, but it's wasteful; the same condition
386+ could be used more efficiently at the <Command>where</Command> stage.)
387+ </para>
388+
389+ <Para>
390+ As an example, we can find the highest low-temperature reading anywhere
391+ with
372392
373393 <ProgramListing>
374394SELECT max(temp_lo) FROM weather;
375395 </ProgramListing>
376396
377- is allowed, while
397+ If we want to know which city (or cities) that reading occurred in,
398+ we might try
378399
379400 <ProgramListing>
380401SELECT city FROM weather WHERE temp_lo = max(temp_lo);
381402 </ProgramListing>
382403
383- is not. However, as is often the case the query can be restated to accomplish
384- the intended result; here by using a <FirstTerm>subselect</FirstTerm>:
404+ but this will not work since the aggregate max() can't be used in
405+ <Command>where</Command>. However, as is often the case the query can be
406+ restated to accomplish the intended result; here by using a
407+ <FirstTerm>subselect</FirstTerm>:
385408 <ProgramListing>
386409SELECT city FROM weather WHERE temp_lo = (SELECT max(temp_lo) FROM weather);
387410 </ProgramListing>
411+ This is OK because the sub-select is an independent computation that
412+ computes its own aggregate separately from what's happening in the outer
413+ select.
388414 </Para>
389415
390416 <Para>
391- Aggregates may also have <FirstTerm>group by</FirstTerm> clauses:
417+ Aggregates are also very useful in combination with
418+ <FirstTerm>group by</FirstTerm> clauses. For example, we can get the
419+ maximum low temperature observed in each city with
392420 <ProgramListing>
393421SELECT city, max(temp_lo)
394422 FROM weather
395423 GROUP BY city;
396424 </ProgramListing>
425+ which gives us one output row per city. We can filter these grouped
426+ rows using <Command>having</Command>:
427+ <ProgramListing>
428+ SELECT city, max(temp_lo)
429+ FROM weather
430+ GROUP BY city
431+ HAVING min(temp_lo) < 0;
432+ </ProgramListing>
433+ which gives us the same results for only the cities that have some
434+ below-zero readings. Finally, if we only care about cities whose
435+ names begin with 'P', we might do
436+ <ProgramListing>
437+ SELECT city, max(temp_lo)
438+ FROM weather
439+ WHERE city like 'P%'
440+ GROUP BY city
441+ HAVING min(temp_lo) < 0;
442+ </ProgramListing>
443+ Note that we can apply the city-name restriction in
444+ <Command>where</Command>, since it needs no aggregate. This is
445+ more efficient than adding the restriction to <Command>having</Command>,
446+ because we avoid doing the grouping and aggregate calculations
447+ for all rows that fail the <Command>where</Command> check.
397448 </Para>
398449 </sect1>
399450 </Chapter>