SQLD에서 점수를 가르는 건 어려운 이론보다 NULL 처리, 조인 조건 위치, 윈도우 함수의 동작 같은 “알고 있다고 착각하기 쉬운” 부분입니다. 오늘은 이 영역에서 결과를 직접 계산해 보는 문제 8개를 준비했습니다. 모든 결과값은 실제로 쿼리를 실행해 확인했습니다.
이 글은 직접 만든 학습용 예상문제이며 실제 시험과 다를 수 있습니다. 최신 출제 범위와 일정은 한국데이터산업진흥원 공식 공지를 꼭 확인하세요.
이 글의 구성
- 공통 테이블 소개 (EMP, DEPT, A, B, X, Y)
- 문제 1~2: NULL 집계와 NULL 비교
- 문제 3~4: GROUP BY·HAVING, LEFT JOIN의 ON과 WHERE
- 문제 5~6: RANK 계열과 누적 합계 윈도우 함수
- 문제 7~8: NOT IN과 NULL, 집합 연산자
- 공부 팁 3가지
공통 테이블
아래 데이터를 기준으로 모든 문제를 풉니다. 빈 칸은 NULL입니다.
EMP(EMPNO, ENAME, DEPTNO, SAL, COMM) 1 KIM 10 300 100 2 LEE 10 300 NULL 3 PARK 20 200 NULL 4 CHOI 20 250 50 5 JUNG 30 400 NULL 6 HAN NULL 150 NULL DEPT(DEPTNO, DNAME) 10 DEV / 20 SALES / 40 HR A(V): 1, 2, 2, 3 B(V): 2, 3, 3, 4 X(V): 1, 2, 3 Y(V): 1, NULL
문제 1. NULL이 섞인 집계 함수
다음 쿼리의 결과 네 값을 쓰시오.
SELECT COUNT(*), COUNT(COMM), SUM(COMM), AVG(COMM) FROM EMP;
정답: 6, 2, 150, 75
COUNT(*)는 NULL 여부와 관계없이 행 수를 세므로 6입니다. COUNT(컬럼)과 SUM, AVG는 NULL을 제외하고 계산합니다. COMM에서 NULL이 아닌 값은 100과 50 두 개뿐이라 합계가 150, 평균은 150을 2로 나눈 75입니다. 6으로 나눈 25가 아니라는 점이 함정입니다.
문제 2. NULL 비교 연산
다음 두 쿼리가 반환하는 행의 수를 각각 쓰시오.
(가) SELECT * FROM EMP WHERE COMM = NULL; (나) SELECT * FROM EMP WHERE DEPTNO <> 10;
정답: (가) 0건, (나) 3건
NULL과의 비교는 참도 거짓도 아닌 UNKNOWN이 되어 WHERE를 통과하지 못합니다. NULL 검사는 반드시 IS NULL, IS NOT NULL을 씁니다. (나)에서 DEPTNO가 10이 아닌 행은 PARK, CHOI, JUNG이고, DEPTNO가 NULL인 HAN은 비교 결과가 UNKNOWN이라 빠집니다. 총 3건입니다.
문제 3. GROUP BY와 HAVING
다음 쿼리의 결과를 쓰시오.
SELECT DEPTNO, SUM(SAL) FROM EMP GROUP BY DEPTNO HAVING COUNT(*) >= 2 ORDER BY DEPTNO;
정답: (10, 600), (20, 450)
GROUP BY가 먼저 그룹을 만들고 HAVING이 그룹 단위로 걸러냅니다. 10번 부서는 2명(300+300), 20번 부서는 2명(200+250)입니다. 30번 부서와 DEPTNO가 NULL인 그룹은 각각 1명이라 제외됩니다. 참고로 GROUP BY에서 NULL은 하나의 그룹으로 묶입니다. 행을 거르는 WHERE, 그룹을 거르는 HAVING이라는 구분을 기억하세요.
문제 4. LEFT JOIN에서 ON과 WHERE의 차이
두 쿼리가 반환하는 행의 수를 각각 쓰시오.
(가) SELECT E.ENAME, D.DNAME
FROM EMP E LEFT OUTER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO AND D.DNAME = 'DEV';
(나) SELECT E.ENAME
FROM EMP E LEFT OUTER JOIN DEPT D
ON E.DEPTNO = D.DEPTNO
WHERE D.DNAME = 'DEV';
정답: (가) 6건, (나) 2건
ON 절의 조건은 “무엇을 붙일지”를 정할 뿐 왼쪽 테이블의 행은 모두 남깁니다. (가)는 EMP 6행이 전부 나오고 KIM, LEE만 DNAME이 DEV이며 나머지는 NULL입니다. (나)는 조인이 끝난 뒤 WHERE가 행을 걸러내므로 DNAME이 DEV인 KIM, LEE 두 행만 남습니다. 외부 조인의 필터를 WHERE에 쓰면 사실상 내부 조인이 되어 버립니다.
문제 5. RANK, DENSE_RANK 비교
다음 쿼리에서 CHOI와 HAN의 R, DR 값을 쓰시오.
SELECT ENAME, SAL,
RANK() OVER (ORDER BY SAL DESC) R,
DENSE_RANK() OVER (ORDER BY SAL DESC) DR
FROM EMP;
정답: CHOI는 R=4, DR=3 / HAN은 R=6, DR=5
급여 내림차순은 JUNG 400, KIM·LEE 300, CHOI 250, PARK 200, HAN 150입니다. RANK는 동순위가 있으면 그 인원만큼 다음 순위를 건너뛰므로 공동 2위 두 명 뒤에 4위가 옵니다. DENSE_RANK는 건너뛰지 않아 3위가 됩니다. ROW_NUMBER는 동점이어도 항상 고유한 번호를 매깁니다.
문제 6. 누적 합계와 기본 윈도우 범위
다음 쿼리에서 KIM과 LEE의 S 값을 쓰시오. (KIM, LEE 모두 급여 300)
SELECT ENAME, SAL,
SUM(SAL) OVER (ORDER BY SAL) S
FROM EMP;
정답: KIM, LEE 모두 1200
윈도우 함수에 ORDER BY만 쓰면 기본 범위는 RANGE UNBOUNDED PRECEDING AND CURRENT ROW입니다. RANGE는 값이 같은 행(동순위)을 모두 현재 행으로 취급하므로, 150+200+250+300+300이 두 행 모두에 적용되어 1200이 됩니다. 행 단위로 누적하고 싶다면 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW를 명시해야 하고, 이때는 한 행이 900, 다음 행이 1200이 됩니다(동점 행의 순서는 정해져 있지 않음).
문제 7. NOT IN과 NULL
다음 두 쿼리가 반환하는 행의 수를 쓰시오.
(가) SELECT * FROM X WHERE V IN (SELECT V FROM Y); (나) SELECT * FROM X WHERE V NOT IN (SELECT V FROM Y);
정답: (가) 1건, (나) 0건
(가)는 V=1만 일치합니다. (나)는 V NOT IN (1, NULL)이 V<>1 AND V<>NULL로 풀리는데, 뒤쪽 조건이 항상 UNKNOWN이라 어떤 행도 참이 되지 않습니다. 서브쿼리 결과에 NULL이 있을 수 있다면 NOT EXISTS를 쓰거나 서브쿼리에서 NULL을 제외해야 합니다.
문제 8. 집합 연산자 행 수
A와 B에 대해 각 연산의 결과 행 수를 쓰시오.
(가) A UNION B (나) A UNION ALL B (다) A INTERSECT B (라) A EXCEPT B
정답: (가) 4, (나) 8, (다) 2, (라) 1
UNION은 중복을 제거해 {1,2,3,4}로 4건이고, UNION ALL은 중복을 그대로 두어 4+4=8건입니다. INTERSECT는 공통값 {2,3}으로 2건입니다. A에서 B를 뺀 결과는 {1} 하나입니다. 오라클에서는 EXCEPT 대신 MINUS를 쓴다는 점도 함께 기억해 두세요.
공부 팁 3가지
- 결과를 눈으로만 풀지 말고, 작은 테이블을 직접 만들어 실행해 보세요. NULL과 조인 문제는 손으로 한 번 확인하면 오래 갑니다.
- 틀린 문제는 어떤 규칙에서 틀렸는지를 한 줄로 적어 두세요. “COUNT(컬럼)은 NULL 제외”처럼 규칙 단위로 모으면 복습이 빨라집니다.
- DBMS마다 문법이 조금씩 다릅니다(MINUS와 EXCEPT, NVL과 COALESCE 등). 시험 범위에 맞춰 오라클 기준과 표준 SQL을 함께 정리하세요.
면책
이 글의 문제는 학습을 위해 직접 만든 예상문제이며 실제 기출과 무관하고 시험과 다를 수 있습니다. 시험 범위, 일정, 합격 기준은 한국데이터산업진흥원 등 공식 공지를 반드시 확인하세요.