읽는 법 — 각 항목은 "무엇이 갈리는가 → 작은 예시 → 외울 한 줄" 순서입니다. 모의고사에서 틀린 문항이 이 열 가지 중 어디에 속하는지 분류해 두면 같은 함정에 두 번 걸리지 않습니다.
1. COUNT(*)와 COUNT(열), 그리고 AVG의 분모
점수 열이 80, NULL, 60인 세 행에서 COUNT(*)는 3, COUNT(점수)는 2, SUM(점수)는 140, AVG(점수)는 70입니다. AVG는 NULL을 뺀 2로 나눕니다. 외울 한 줄: 집계 함수는 NULL을 무시하고, 행 수를 세는 것은 COUNT(*)뿐입니다.
2. OUTER JOIN에서 조건을 ON에 두느냐 WHERE에 두느냐
부서 LEFT OUTER JOIN 사원 ON 부서.부서코드 = 사원.부서코드 AND 사원.급여 >= 300이면 급여 조건에 걸리는 사원이 없는 부서도 NULL과 함께 남습니다. 같은 조건을 WHERE 사원.급여 >= 300으로 옮기면 그 부서 행은 사라져 INNER JOIN과 같아집니다. Oracle의 (+) 표기에서는 (+)가 붙은 조건만 ON 조건으로 취급됩니다.
3. UNION은 중복을 지우고, UNION ALL은 남긴다
왼쪽 4행과 오른쪽 3행에 같은 행이 1개 있으면 UNION ALL은 7행, UNION은 6행입니다. INTERSECT는 양쪽에 모두 있는 1행, MINUS(EXCEPT)는 왼쪽에서 오른쪽을 뺀 3행입니다. 집합 연산 결과의 정렬은 마지막 SELECT 뒤의 ORDER BY 하나로만 합니다.
4. ROLLUP과 CUBE의 행 수
지역 2가지 × 상품 3가지 조합이 모두 있는 데이터에서 GROUP BY ROLLUP(지역, 상품)은 상세 6행 + 지역 소계 2행 + 총계 1행 = 9행, CUBE(지역, 상품)는 여기에 상품 소계 3행이 더해져 12행입니다. GROUPING(열) 값은 소계 행에서 1, 상세 행에서 0입니다. ROLLUP의 인수 순서를 바꾸면 소계가 붙는 열이 바뀝니다.
5. RANK·DENSE_RANK·ROW_NUMBER의 동점 처리
점수 90, 90, 80에 ORDER BY 점수 DESC를 걸면 RANK는 1, 1, 3, DENSE_RANK는 1, 1, 2, ROW_NUMBER는 1, 2, 3입니다. 동점 뒤 순위가 건너뛰면 RANK, 이어지면 DENSE_RANK, 동점이 없는 것처럼 번호가 붙으면 ROW_NUMBER입니다.
6. 윈도우 프레임 — ROWS와 RANGE, 기본 프레임
SUM(금액) OVER (ORDER BY 일자)는 프레임을 생략하면 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW라서 같은 일자의 행들은 모두 같은 누적 값을 가집니다. ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING은 앞뒤 한 행씩 세 행의 합이고 첫 행과 마지막 행은 두 행만 더합니다. LAG·LEAD는 지정한 만큼 앞뒤 행 값을 가져오며 없으면 NULL(또는 지정한 기본값)입니다.
7. CONNECT BY의 전개 방향
START WITH 관리자번호 IS NULL CONNECT BY PRIOR 사원번호 = 관리자번호는 최상위 관리자에서 부하로 내려가는 순방향 전개입니다. PRIOR가 관리자번호 쪽에 붙으면(CONNECT BY 사원번호 = PRIOR 관리자번호) 특정 사원에서 상사로 올라가는 역방향입니다. LEVEL은 시작 행이 1이고, ORDER SIBLINGS BY는 같은 부모 아래 형제만 정렬해 계층 모양을 유지합니다.
8. ROWNUM은 정렬보다 먼저 붙는다
SELECT * FROM 사원 WHERE ROWNUM <= 3 ORDER BY 급여 DESC는 "아무 3행"을 뽑은 뒤 정렬합니다. 급여 상위 3명을 뽑으려면 정렬한 인라인 뷰를 감싸고 바깥에서 ROWNUM <= 3을 걸어야 합니다. ROWNUM > 1 같은 조건은 첫 행이 1이 되지 못해 항상 0건입니다. 표준 구문은 ORDER BY … FETCH FIRST 3 ROWS ONLY, SQL Server는 SELECT TOP 3 … ORDER BY입니다.
9. NOT IN과 NULL
서브쿼리 결과에 NULL이 하나라도 있으면 NOT IN은 어떤 행도 참이 되지 못해 결과가 0건입니다. IN은 NULL이 있어도 일치하는 값만 찾으므로 정상 동작합니다. 같은 뜻으로 쓰려면 NOT EXISTS로 바꾸거나 서브쿼리에 WHERE 열 IS NOT NULL을 붙입니다.
10. DECODE와 CASE의 NULL 비교
Oracle의 DECODE(열, NULL, '없음', '있음')은 열이 NULL이면 '없음'을 돌려주지만, CASE 열 WHEN NULL THEN … 은 NULL = NULL 비교가 거짓이라 절대 매칭되지 않습니다. CASE로 쓰려면 CASE WHEN 열 IS NULL THEN … 으로 써야 합니다. 같은 맥락에서 WHERE 열 = NULL은 아무 행도 돌려주지 않고 IS NULL을 써야 합니다.
이 유형으로 바로 연습
- SQLD 실전 모의고사 10회 500문항 →결과표 보기는 위 함정 하나씩에 대응하는 오답으로 구성 · 해설에 어느 행이 왜 생기고 빠지는지 명시