2.7. 聚集函數

和大多數其它關係資料庫產品一樣, PostgreSQL 支援聚集函數。 一個聚集函數從多個輸入行中計算出一個結果。 比如,我們有在一個行集合上計算 count(數目), sum(和),avg(均值), max(最大值)和min(最小值)的函數。

比如,我們可以用下面的語句找出所有記錄中低溫中的最高溫度

SELECT max(temp_lo) FROM weather;

 max
-----
  46
(1 row)

如果我們想知道該讀數發生在哪個城市,我們可以用

SELECT city FROM weather WHERE temp_lo = max(temp_lo);     WRONG

不過這個方法不能運轉,因為聚集 max 不能用於 WHERE 子句中。 (存在這個限制是因為 WHERE 子句決定哪些行可以進入聚集階段;因此它必需在聚集函數之前計算。) 不過,我們通常都可以用其它方法實現我們的目的;這裡我們就可以使用子查詢

SELECT city FROM weather
    WHERE temp_lo = (SELECT max(temp_lo) FROM weather);

     city
---------------
 San Francisco
(1 row)

這樣做是 OK 的,因為子查詢是一次獨立的計算,它獨立於外層的查詢計算出自己的聚集。

聚集同樣也常用於 GROUP BY 子句。比如, 我們可以獲取每個城市低溫的最高值

SELECT city, max(temp_lo)
    FROM weather
    GROUP BY city;

     city      | max
---------------+-----
 Hayward       |  37
 San Francisco |  46
(2 rows)

這樣給我們每個城市一個輸出。 每個聚集結果都是在匹配該城市的行上面計算的。 我們可以用 HAVING 過濾這些分組:

SELECT city, max(temp_lo)
    FROM weather
    GROUP BY city
    HAVING max(temp_lo) < 40;

  city   | max
---------+-----
 Hayward |  37
(1 row)

這樣就只給出那些 temp_lo 數值曾經有低於 40 度溫度的城市。 最後,如果我們只關心那些名字以 "S" 開頭的城市,我們可以用

SELECT city, max(temp_lo)
    FROM weather
    WHERE city LIKE 'S%'(1)
    GROUP BY city
    HAVING max(temp_lo) < 40;

(1)
LIKE 做模式匹配,在 Section 9.7 裡有解釋。

理解聚集和SQLWHERE 以及 HAVING 子句之間的關係對我們非常重要。 WHEREHAVING 的基本區別如下: WHERE 在分組和聚集計算之前選取輸入行(因此,它控制哪些行進入聚集計算), 而 HAVING 在分組和聚集之後選取分組的行。 因此,WHERE 子句不能包含聚集函數; 因為試圖用聚集函數判斷那些行輸入給聚集運算是沒有意義的。 相反,HAVING 子句總是包含聚集函數。 (嚴格說來,您可以寫不使用聚集的 HAVING 子句, 但這樣做只是白費勁。同樣的條件可以更有效地用於 WHERE 階段。)

在前面的例子裡,我們可以在 WHERE 裡應用城市名稱限制,因為它不需要聚集。 這樣比在 HAVING 裡增加限制更加高效,因為我們避免了為那些未透過 WHERE 檢查的行進行分組和聚集計算。