스파르타 내일배움캠프(25.12.01~)

[개념정리] Having + Subquery

0️⃣ 2025. 12. 29. 21:30

Pattern 1) 집계값을 상수와 비교

Q. 총 구매금액이 100만 이상인 고객
SELECT customer_id,
       SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING SUM(amount) >= 1000000;

Next : “1000000” 자리에 서브쿼리로 만든 값을 넣는 게 핵심!

Pattern 2) 비상관 서브쿼리
: 서브쿼리가 독립적인 결과를 출력

Q. 고객별 총구매금액이 전체 고객 평균 총구매금액 이상인 고객

 

--Step 1: 고객별 총구매(기준 데이터)
SELECT customer_id, SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id;

--Step 2: “전체 평균”을 구하려면?
SELECT AVG(total_spent)
FROM (
  SELECT customer_id, SUM(amount) AS total_spent
  FROM orders
  GROUP BY customer_id
) t;

--Step 3: HAVING에 넣기
SELECT customer_id,
       SUM(amount) AS total_spent
FROM orders
GROUP BY customer_id
HAVING SUM(amount) >= (
  SELECT AVG(total_spent)
  FROM (
    SELECT customer_id, SUM(amount) AS total_spent
    FROM orders
    GROUP BY customer_id
  ) t
);

 

Pattern 3) 상관 서브쿼리 🔴
: 서브쿼리에서 바깥 별칭을 참조

  1. 비교 연산자(=, >=, <=) 를 쓰면
    → 서브쿼리는 보통 1개의 값을 반환해야 함
    (여러 값이면 INANYALL 같은 문법이 필요)
  2. HAVING은 그룹 기준 조건이라서
    → SUM/COUNT/AVG 같은 집계가 자주 들어감
  3. “전체 평균/최대”를 비교할 때는즉 서브쿼리가 2단이 되는 경우가 많음
    (고객별 집계) → (그걸 다시 평균/최대)
Q. 국가별로 고객 총구매를 구하고, 그 국가에서 최대값과 같은 고객만 남기기

 

--Step 1: 국가+고객별 총구매
SELECT country, customer_id, SUM(amount) AS total_spent
FROM orders
GROUP BY country, customer_id;

--Step 2: “같은 국가 안에서” 최대 total_spent 구하기
SELECT MAX(total_spent)
FROM (
  SELECT customer_id, SUM(amount) AS total_spent
  FROM orders
  WHERE country = (바깥 country) --바깥 별칭 참조
  GROUP BY customer_id
) x;

--Step 3: HAVING에 적용(전체 구조)
SELECT country,
       customer_id,
       SUM(amount) AS total_spent
FROM orders o
GROUP BY country, customer_id
HAVING SUM(amount) = (
  SELECT MAX(t.total_spent)
  FROM (
    SELECT customer_id, SUM(amount) AS total_spent
    FROM orders
    WHERE country = o.country --바깥 별칭 참조
    GROUP BY customer_id
  ) t
);