2.7. 집계 함수

다른 대부분의 데이터베이스 제품들과 마찬가지로 PostgreSQL에서도 집계 함수 (aggregate function)를 사용할 수 있습니다. 집계 함수란 입력이 여러개의 로우이고, 출력이 하나인 결과인 것을 말합니다. 테이블의 전체 로우 수를 구하는 count, 평균(avg), 총합(sum), 최대값(max), 최소값(min) 등등이 이런 함수들 입니다.

다음은 최고 기온을 구하는 쿼리입니다:

SELECT max(temp_lo) FROM weather;

 max
-----
  46
(1 row)

여기서 이 최고 기온의 해당 도시가 무엇인지 알기 위해서 다음과 같이 생각할 수도 있겠지요:

SELECT city FROM weather WHERE temp_lo = max(temp_lo);     잘못된 구문

하지만, 윗 쿼리의 결과는 오류를 냅니다. 왜냐하면, WHERE 절 다음에는 집계 함수를 사용할 수 없기 때문입니다. (이렇게 되는 이유는 윗 예를 들어, max 함수 자체가 select를 하지 않으면 나올 수 없는 값이기 때문입니다) 이런 문제는 다음과 같은 서브쿼리 (subquery)로 풀어야지 원하는 결과를 볼 수 있습니다:

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

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

윗 구문에서 where 다음에 나오는 (select ....) 구문을 서브쿼리(subquery)라고 합니다. 하나의 쿼리에서 서브쿼리가 있으면, 서버는 먼저 서브쿼리를 처리하고, 그 결과를 서브쿼리가 있는 자리에 대치시키고 다시 쿼리를 합니다.

집계 함수는 일반적으로 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)

이것은 각 도시별 최고 기온이 40(주, 아마 화씨일듯)도가 되지 않는 목록들을 보는 것입니다. 마지막으로 도시 이름이 S로 시작하는 도시들 가운데서 위와 같은 조건에 일치하는 자료를 찾으려면 다음과 같은 쿼리가 사용됩니다:

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

(1)

LIKE 연산자는 문자열 패턴 매칭 관련 연산자인데, 자세한 것은 9.7절을 참조하세요.

집계 함수를 사용 할 때는 WHERE 절과 HAVING 절의 관계를 반드시 숙지하고 있어야합니다. WHERE 절은 조회할 집계되지 않은 자료에 대한 조건이고, HAVING은 집계된 자료에 대한 조건입니다. 그래서, WHERE 절의 조건으로 HAVING 절이 사용될 수 없습니다. 일반적으로 HAVING 절 다음에는 집계 함수가 사용됩니다. 물론 더 깊게 이야기하면, WHERE 다음에 HAVING이 올 수 있고, HAVING 다음에 집계 함수가 오지 않을 수도 있습니다. 하지만, 이런 골치 아픈 부분에 대해서는 이곳에서 언급해야할 이유가 없을 것 같습니다. 여기서는 단지, WHERE 다음에는 집계할 대상에 대한 조건이, HAVING 다음에 그 자료를 집계한 값에 대한 조건을 사용한다는 것만 이해하시면 됩니다.

앞 예제에서, 집계 작업을 하지 않고, WHERE 을 이용해서, 특정 도시만 그 대상으로 할 수 있습니다. 이것은 HAVING 예약어를 사용하는 방식보다 성능이 좋습니다. 왜냐하면, WHERE 절을 이용해서 집계 작업 대상 자체에서 제외했기 때문입니다.