GROUP BY 없이 HAVING 사용

Suhyeon Lee·2024년 10월 26일
0

GROUP BY와 HAVING은 짝꿍이다?

  • SQL에서 HAVING은 특정 그룹에 대한 집계 함수에 조건을 달기 위해서 사용
    • 그래서 주로 GROUP BY와 함께 사용하는 경우가 많음
  • 하지만 엄연히 말하면 GROUP BY가 필수인 것은 아님!
    • HAVING이 주로 GROUP BY절 뒤에 오는 것은 맞지만, 그렇지 않은 경우도 반드시 존재함
    • 테이블 전체를 하나의 그룹으로 집계 조건을 달고 싶을 때는 GROUP BY 없이도 사용이 가능
  • 예를 들면 아래와 같은 경우가 GROUP BY 없이 단독 HAVING이 존재하는 경우임
SELECT COUNT(*)
FROM 테이블
HAVING COUNT(*) > 1

예제 1

  • 아이템의 CNT값들 중 MAX 값이 100이 넘을 경우에만 CNT의 총 합을 반환하고, 아닐 경우 값을 반환하지 않도록 쿼리문 작성
SELECT SUM(CNT) AS result
FROM sql_test_a;
HAVING MAX(CNT) > 100
-- 결과 : 300
  • pencil의 CNT 값이 120으로 100이 넘기 때문에, 결과는 CNT들의 총합인 300을 반환

  • HAVING이 아닌 WHERE절을 사용할 경우 오류 발생

-- 오류 발생 쿼리
SELECT SUM(CNT) AS result
FROM sql_test_a;
WHERE MAX(CNT) > 100

예제 2

nameprice
a10,000
b4,000
c7,000
d6,000
a6,000
a7,000
  • 테이블 전체를 하나의 그룹으로 잡고 SUM, MAX, AVG 같은 함수에 조건을 달고 싶을 때 바로 적용 가능
SELECT
  SUM(price)
FROM
  table
HAVING
  SUM(price) > 20000
;  
SUM(PRICE)
40,000

→ 전체 합계가 2만이 넘기 때문에 정상적으로 조회가 됨

  • 또, HAVING 조건문에서는 SUM을 달았지만 SELECT에는 다른 항목을 표시해도 됨
SELECT
  MAX(price) AS max_p
  , AVG(price) AS avg_p
  , COUNT(name) AS cnt_p
  , COUNT(DISTINCT name) AS cnt_dist_p
FROM
  table
HAVING
  SUM(price) > 20000
;
max_pavg_pcnt_pcnt_dist_p
10,0006,666.66…64
  • 단, 테이블 전체를 하나의 그룹으로 묶어서 HAVING 조건을 달았기 때문에 SELECT에서 각각의 name, price 같은 값을 나타낼 수는 없음
SELECT
  name
FROM
  table
HAVING
  SUM(price) > 20000
;
# 아래와 같은 출력
# SQL Error [937][42000]: ORA-00937: 단일 그룹의 합수가 아닙니다
  • FROM>WHERE>GROUP BY>HAVING>SELECT>ORDER BY 순서대로 처리되기 때문에, 위의 예제 상황에서 집계 대상이 되는 테이블에 WHERE 조건문을 거는 것도 가능
SELECT
  SUM(price)
FROM
  table
WHERE
  price > 5000
HAVING
  SUM(price) > 20000
;
SUM(PRICE)
36,000

→ WHERE 조건문으로 price가 5000 이상인 row에 대해서만 sum을 하도록 했기 때문에 price가 4000인 row 가 집계에서 제외됨

SELECT
  SUM(price)
FROM
  table
WHERE
  name <> '가'
HAVING
  SUM(price) > 20000
;
SUM(PRICE)

→ name이 '가' 가 아닌 행들만 sum(price)하면 20000이 넘지 않아서 표시되지 않음

  • 위와 같은 상황에서 name을 기준으로 group by를 하게 된다면 '가','나','다','라','마'가 각각의 그룹이 되어 having 집계함수는 각 그룹의 집계에 대해 적용됨
    • 우리가 흔히 쓰는 group by + having의 구성
SELECT
  name
  , SUM(price)
FROM
  table
WHERE
  price > 5000
GROUP BY
  name
HAVING
  SUM(price) > 20000
;
NAMESUM(PRICE)
a23,000

→ 테이블에서 name으로 group by를 했을 시 20000이 넘는 '가' 그룹만 정상적으로 표시

profile
2 B R 0 2 B

0개의 댓글