[SQL&Database] 서브쿼리와 그룹화 함수

Comely·2025년 6월 9일

SQL

목록 보기
3/6

서브쿼리 (Subquery) 기본 개념

서브쿼리란?

SELECT 쿼리 안에 다른 SELECT 쿼리를 넣는 문법으로, 복잡한 조건을 한 번에 처리할 수 있게 해줍니다.

기본 예제: 평균보다 높은 사용금액 조회

-- 1단계: 평균 구하기
SELECT AVG(사용금액) FROM card;  -- 결과: 245000

-- 2단계: 평균보다 높은 값 조회
SELECT * FROM card WHERE 사용금액 > 245000;

-- 서브쿼리로 한번에 처리
SELECT * FROM card WHERE 사용금액 > 
  (SELECT AVG(사용금액) FROM card);

서브쿼리 사용 규칙

  1. 괄호 필수: 서브쿼리는 반드시 ( ) 괄호로 감싸야 함
  2. 단일 값 반환: 대부분의 경우 하나의 값만 반환해야 함
  3. 데이터 위치: 문자나 숫자가 들어갈 곳에만 사용 가능

다양한 위치에서 서브쿼리 사용

WHERE 절에서 사용

-- 평균 사용금액보다 높은 고객 조회
SELECT * FROM card 
WHERE 사용금액 > (SELECT AVG(사용금액) FROM card);

SELECT 절에서 사용

-- 각 고객의 사용금액과 평균 사용금액 함께 출력
SELECT 고객명, 사용금액, (SELECT AVG(사용금액) FROM card) AS 평균금액
FROM card;

-- 평균과의 차이 계산
SELECT 고객명, 사용금액, 
       사용금액 - (SELECT AVG(사용금액) FROM card) AS 평균대비차이
FROM card;

IN 절에서 사용

-- 블랙리스트 테이블 생성 후 해당 고객들의 사용금액 조회
SELECT 사용금액 FROM card 
WHERE 고객명 IN (SELECT 이름 FROM blacklist);

실무 활용 예제

-- 고객등급이 '패밀리'인 사람들의 평균 연체횟수보다 연체횟수가 높은 사람 수
SELECT COUNT(*) FROM card 
WHERE 연체횟수 > (
  SELECT AVG(연체횟수) FROM card WHERE 고객등급 = '패밀리'
);

GROUP BY - 그룹화를 통한 집계

GROUP BY 기본 문법

같은 값을 가진 행들을 그룹으로 묶어서 집계 함수를 적용할 때 사용합니다.

-- 고객등급별로 그룹화
SELECT 고객등급 FROM card GROUP BY 고객등급;

-- 고객등급별 고객 수 계산
SELECT 고객등급, COUNT(고객명) FROM card GROUP BY 고객등급;

-- 고객등급별 평균 사용금액
SELECT 고객등급, AVG(사용금액) FROM card GROUP BY 고객등급;

집계 함수와 GROUP BY 조합

-- 고객등급별 다양한 통계
SELECT 고객등급,
       COUNT(*) AS 고객수,
       AVG(사용금액) AS 평균사용금액,
       MAX(사용금액) AS 최대사용금액,
       MIN(사용금액) AS 최소사용금액,
       SUM(사용금액) AS 총사용금액
FROM card 
GROUP BY 고객등급;

HAVING - GROUP BY 결과 필터링

GROUP BY로 그룹화된 결과를 필터링할 때 사용합니다.

-- 고객 수가 2명 이상인 등급만 조회
SELECT 고객등급, COUNT(*) AS 고객수
FROM card 
GROUP BY 고객등급 
HAVING COUNT(*) >= 2;

-- VIP 등급만 필터링
SELECT 고객등급, COUNT(고객명) FROM card 
GROUP BY 고객등급 
HAVING 고객등급 = 'vip';

WHERE vs HAVING 차이점

  • WHERE: 원본 테이블 데이터를 필터링 (GROUP BY 전에 실행)
  • HAVING: GROUP BY 결과를 필터링 (GROUP BY 후에 실행)
-- WHERE와 HAVING 함께 사용
SELECT 고객등급, COUNT(고객명) FROM card 
WHERE 연체횟수 = 0           -- 원본 데이터 필터링
GROUP BY 고객등급 
HAVING 고객등급 = 'vip';     -- 그룹화 결과 필터링

SQL 실행 순서

SELECT 고객등급, AVG(사용금액)  -- 5. 최종 결과 선택
FROM card                      -- 1. 테이블 선택
WHERE 연체횟수 = 0            -- 2. 원본 데이터 필터링
GROUP BY 고객등급             -- 3. 그룹화
HAVING AVG(사용금액) > 200000 -- 4. 그룹 결과 필터링
ORDER BY 고객등급;           -- 6. 정렬

조건부 값 처리: IF와 CASE

IF 함수

두 가지 경우만 처리할 때 사용하는 간단한 조건문입니다.

-- 기본 문법
IF(조건식, 조건이_참일때_값, 조건이_거짓일때_값)

-- 사용금액이 20만원 이상이면 '우수', 미만이면 '거지'
SELECT 고객명, 사용금액, 
       IF(사용금액 > 200000, '우수', '거지') AS 등급
FROM card;

-- 연체 여부 확인
SELECT 고객명, 연체횟수,
       IF(연체횟수 = 0, '정상', '연체') AS 상태
FROM card;

CASE 문법

세 가지 이상의 경우를 처리할 때 사용하는 확장된 조건문입니다.

-- 기본 문법
CASE 
  WHEN 조건식1 THEN1
  WHEN 조건식2 THEN2
  WHEN 조건식3 THEN3
  ELSE 기본값
END

-- 사용금액에 따른 등급 분류
SELECT 고객명, 사용금액,
CASE 
  WHEN 사용금액 >= 300000 THEN 'vip'
  WHEN 사용금액 >= 200000 THEN '로열'
  WHEN 사용금액 >= 100000 THEN '준수'
  ELSE '그지'
END AS 신규등급
FROM card;

집계 함수와 CASE 조합

-- 등급별 점수 합계 (vip=3점, 로열=2점, 패밀리=1점)
SELECT SUM(
  CASE
    WHEN 고객등급 = 'vip' THEN 3 
    WHEN 고객등급 = '로열' THEN 2 
    ELSE 1
  END
) AS 총점수
FROM card;

-- 조건별 집계
SELECT 
  SUM(CASE WHEN 사용금액 >= 300000 THEN 1 ELSE 0 END) AS 고액고객수,
  SUM(CASE WHEN 연체횟수 > 0 THEN 1 ELSE 0 END) AS 연체고객수
FROM card;

실전 활용 예제

문제 1: 장부 조작하기

사용금액 30만원 이상은 50% 증액, 미만은 10% 증액하여 총합 계산

SELECT SUM(
  CASE 
    WHEN 사용금액 >= 300000 THEN 사용금액 * 1.5
    ELSE 사용금액 * 1.1
  END
) AS 조작된총합
FROM card;

문제 2: 등급 변동 대상자 찾기

현재 등급과 새로운 등급 기준이 다른 고객들만 조회

SELECT 고객명, 사용금액, 고객등급,
CASE 
  WHEN 사용금액 >= 300000 THEN 'vip'
  WHEN 사용금액 >= 200000 THEN '로열'
  ELSE '패밀리'
END AS 신규등급
FROM card
WHERE 고객등급 != CASE 
  WHEN 사용금액 >= 300000 THEN 'vip'
  WHEN 사용금액 >= 200000 THEN '로열'
  ELSE '패밀리'
END;

문제 3: 연체횟수별 고객 분포

-- 연체횟수별 고객 수 (1명인 경우 제외)
SELECT 연체횟수, COUNT(*) AS 고객수
FROM card 
GROUP BY 연체횟수 
HAVING COUNT(*) > 1
ORDER BY 연체횟수;

문제 4: 등급별 사용금액 격차

-- 등급별 최대/최소 사용금액 비율
SELECT 고객등급, 
       MAX(사용금액) AS 최대금액,
       MIN(사용금액) AS 최소금액,
       ROUND(MAX(사용금액) / MIN(사용금액), 2) AS 격차비율
FROM card 
GROUP BY 고객등급 
ORDER BY 고객등급;

고급 활용 팁

서브쿼리 최적화

-- 비효율적: 매번 서브쿼리 실행
SELECT *, (SELECT AVG(사용금액) FROM card) FROM card;

-- 효율적: 변수나 임시 테이블 활용 고려
-- (실제로는 대부분의 DBMS가 자동 최적화)

GROUP BY와 ORDER BY 조합

-- 등급별 평균 사용금액을 높은 순으로 정렬
SELECT 고객등급, AVG(사용금액) AS 평균사용금액
FROM card 
GROUP BY 고객등급 
ORDER BY 평균사용금액 DESC;

복잡한 조건의 CASE 문

-- 여러 컬럼을 고려한 등급 산정
SELECT 고객명,
CASE 
  WHEN 사용금액 >= 300000 AND 연체횟수 = 0 THEN 'VIP'
  WHEN 사용금액 >= 200000 AND 연체횟수 <= 1 THEN '우수'
  WHEN 연체횟수 > 3 THEN '주의'
  ELSE '일반'
END AS 종합등급
FROM card;

이러한 기능들을 조합하면 복잡한 비즈니스 로직을 SQL로 구현할 수 있으며, 데이터 분석과 보고서 작성에 매우 유용합니다.

profile
App, Web Developer

0개의 댓글