[SQLD] SQL 개발자 기출유형 모의고사 1회
SQLD SQL 개발자 실전 모의고사

SQL 개발자 기출유형 모의고사 1회

총 50문항 · 객관식 · A4 약 1장

1 / 1
A4정답 포함
SQLD SQL 개발자 실전 모의고사모두CBT · moducbt.com

SQL 개발자 기출유형 모의고사 1회

총 50문항 · 객관식 · 정답·해설 포함
문제 1
데이터 모델링의 유의점 중 비유연성(Inflexibility)에 해당하는 설명은?
1수정된 값과 안 된 값이 서로 어긋난다
2복잡한 현실을 핵심 위주로 단순화한다
3작은 업무 변화에도 모델을 크게 고친다
4같은 정보를 여러 엔터티에 반복 저장한다
정답 및 해설

비유연성은 데이터 정의를 프로세스와 분리하지 못해 작은 업무 변화에도 모델을 크게 고쳐야 하는 상태를 말한다.

모델링 유의점은 중복(Duplication)·비유연성·비일관성(Inconsistency) 세 가지이며, 단순화·추상화·명확화는 모델링의 특징에 해당한다.

  • 같은 정보를 여러 곳에 반복 저장하는 것은 중복이다.
  • 수정된 값과 그렇지 않은 값이 어긋나는 것은 비일관성이다.
  • 현실을 핵심 위주로 단순화하는 것은 유의점이 아니라 모델링의 특징이다.
문제 2
다음 ERD의 엔터티를 발생 시점에 따라 분류한 것으로 옳은 것은?

그림

1고객은 중심, 주문변경이력은 행위 엔터티
2고객·지점은 기본, 주문은 중심 엔터티
3지점은 행위, 주문은 기본 엔터티
4주문은 기본, 주문변경이력은 중심 엔터티
정답 및 해설

다른 엔터티에 의존하지 않고 독립적으로 생성되는 고객·지점은 기본 엔터티이고, 이들로부터 발생하는 업무의 중심인 주문은 중심 엔터티이다.

주문변경이력처럼 부모 엔터티로부터 발생하고 내용이 자주 바뀌거나 계속 누적되는 엔터티는 행위 엔터티로 분류한다.

  • 주문은 고객·지점으로부터 발생하므로 기본 엔터티가 아니다.
  • 고객은 독립적으로 생성되므로 중심이 아니라 기본 엔터티이다.
  • 지점은 행위가 아니라 기본 엔터티이고 주문은 중심 엔터티이다.
문제 3
[주문] 엔터티의 속성을 분류한 것으로 적절하지 않은 것은?
1배송주소 - 더 나눌 수 없는 단일 속성
2주문번호 - 식별용으로 만든 설계 속성
3주문일자 - 업무에서 나온 기본 속성
4총주문금액 - 계산으로 얻는 파생 속성
정답 및 해설

시·구·동·상세주소로 나눌 수 있는 배송주소는 복합 속성(Composite Attribute)이므로 단일 속성으로 본 분류가 잘못되었다.

속성은 특성에 따라 기본·설계·파생 속성으로, 분해 여부에 따라 단일·복합 속성으로, 값의 개수에 따라 단일값·다중값 속성으로 나뉜다.

  • 주문일자는 업무에서 바로 도출되는 기본 속성이다.
  • 일련번호인 주문번호는 식별을 위해 새로 만든 설계 속성이다.
  • 상세 금액을 합산해 얻는 총주문금액은 파생 속성이다.
문제 4
관계를 '각각의 고객은 때때로 여러 건의 주문을 한다'처럼 읽을 때, '때때로'를 결정하는 관계 표기 요소는?
1관계차수
2관계선택사양
3관계명
4식별/비식별 구분
정답 및 해설

'반드시/때때로'는 관계에 참여하는 쪽이 필수인지 선택인지를 나타내는 관계선택사양(Optionality)이 결정한다.

관계는 관계명(Membership)·관계차수(Cardinality)·관계선택사양으로 표기하며, '하나 또는 여러'는 차수에, '반드시·때때로'는 필수(|)·선택(○) 표기에 대응한다.

  • 관계명은 '주문한다'처럼 관계의 이름을 나타낸다.
  • 관계차수는 1:1·1:M처럼 참여하는 건수를 나타낸다.
  • 식별/비식별 구분은 부모 식별자를 상속하는 방식이다.
문제 5
다음 ERD에서 [수강] 엔터티의 주식별자에 대한 설명으로 옳은 것은?

그림

1두 부모 식별자로 이루어진 복합식별자다
2강의코드는 강의 엔터티의 보조식별자다
3학번은 수강이 스스로 만든 내부식별자다
4업무와 무관하게 만든 인조식별자다
정답 및 해설

수강의 주식별자는 학생과 강의로부터 식별 관계로 상속받은 학번·강의코드 두 속성으로 이루어진 복합식별자이다.

관계를 통해 다른 엔터티에서 받아 온 식별자는 외부식별자이며, 업무에 실제 존재하는 값이므로 본질식별자에 해당한다.

  • 학번은 학생에서 상속된 외부식별자로, 스스로 생성된 내부식별자가 아니다.
  • 강의코드는 강의 엔터티의 주식별자이다.
  • 순번처럼 임의로 만든 값이 아니므로 인조식별자가 아니다.
문제 6
제1정규형을 만족하는 엔터티를 제2정규형(2NF)으로 정규화할 때 제거하는 종속은?
1이행 함수 종속
2조인 종속
3다치 종속
4부분 함수 종속
정답 및 해설

주식별자 일부에만 종속되는 부분 함수 종속을 제거하는 단계는 제2정규형(2NF)이다.

예를 들어 (주문번호, 상품코드)가 주식별자인데 상품명이 상품코드에만 종속되면, 상품명을 상품 엔터티로 분리해야 한다.

  • 일반 속성 사이의 이행 함수 종속은 제3정규형에서 제거한다.
  • 다치 종속은 제4정규형에서 제거한다.
  • 조인 종속은 제5정규형에서 제거한다.
문제 7
다음 ERD를 바탕으로 고객명과 주문한 상품명을 함께 조회할 때, 조인에 대한 설명으로 옳은 것은?

그림

1주문과 주문상세는 주문번호로 조인한다
2상품은 주문과 상품코드로 조인한다
3고객과 상품은 고객번호로 바로 조인한다
4주문상세는 고객번호로 고객과 조인한다
정답 및 해설

주문상세는 주문과 식별 관계로 연결되어 주문번호를 상속받으므로, 두 테이블은 주문번호로 조인한다.

고객명과 상품명을 함께 얻으려면 고객→주문→주문상세→상품 순으로 관계마다 PK-FK 쌍을 하나씩, 모두 3개의 조인 조건으로 연결한다.

  • 고객과 상품 사이에는 직접 관계가 없어 공통 속성이 없다.
  • 주문상세에는 고객번호가 없어 주문을 거쳐야 고객과 연결된다.
  • 주문에는 상품코드가 없고 상품코드는 주문상세가 가진다.
문제 8
주문 1건을 등록할 때 주문과 주문상세가 반드시 함께 생성되어야 한다. 이를 데이터 모델에 표현하는 방법으로 가장 적절한 것은?
1상세를 주문의 다중값 속성으로 둔다
2두 엔터티를 별도 트랜잭션으로 나눈다
3주문상세 참여를 선택(○)으로 표기한다
4두 엔터티 관계를 양쪽 필수로 표기한다
정답 및 해설

주문과 주문상세가 한 단위로 함께 생성되어야 한다면 두 엔터티의 관계를 양쪽 필수로 표기해 하나의 트랜잭션으로 처리됨을 드러낸다.

이 표기는 주문 없는 상세나 상세 없는 주문이 생기지 않도록 두 INSERT를 한 트랜잭션으로 묶어야 한다는 것을 알려 준다.

  • 주문상세 참여를 선택으로 두면 상세 없는 주문을 허용하는 모델이 된다.
  • 별도 트랜잭션으로 나누면 한쪽만 저장되는 불일치가 생길 수 있다.
  • 상세를 다중값 속성으로 두면 제1정규형을 위반한다.
문제 9
다음 [직원] 테이블에 SQL을 실행했을 때 A, B, C, D 값을 순서대로 나열한 것은?

[직원]

사번이름급여수당
1윤서30060
2도윤250(null)
3하준4000
4시우350(null)
5지호20030
SELECT COUNT(*) AS A, COUNT(수당) AS B, AVG(수당) AS C,
       SUM(급여 + 수당) AS D
  FROM 직원;
15, 3, 18, 1590
25, 5, 18, 990
33, 3, 30, 990
45, 3, 30, 990
정답 및 해설

COUNT(수당)·AVG(수당)는 NULL을 제외하고 계산하고, 급여+수당처럼 NULL이 섞인 산술 연산은 결과가 NULL이 되어 SUM에서 빠진다.

A는 전체 5행, B는 0을 포함해 수당이 있는 3행, C는 (60+0+30)/3=30, D는 360+400+230=990이다.

  • 평균 18은 NULL을 0으로 보고 5행으로 나눈 값이다.
  • 1590은 NULL을 0으로 본 SUM(급여)+SUM(수당)의 값이다.
  • COUNT(*)는 NULL 여부와 관계없이 모든 행을 세므로 3이 아니다.
문제 10
본질식별자 대신 인조식별자(일련번호)를 주식별자로 쓸 때의 단점으로 옳은 것은?
1자식으로 갈수록 PK 속성 수가 늘어난다
2조인 조건이 여러 속성으로 복잡해진다
3업무 규칙이 바뀌면 PK 값을 고쳐야 한다
4같은 업무 데이터의 중복 입력을 막기 어렵다
정답 및 해설

인조식별자는 업무와 무관한 일련번호라서 본질 속성에 유니크 제약이 없으면 같은 데이터가 중복 입력될 수 있고, 이를 막으려면 추가 인덱스가 필요하다.

반대로 본질식별자는 업무 의미를 그대로 담아 정합성 확인에 유리하지만 PK가 길고 복잡해지기 쉽다.

  • 자식으로 내려갈수록 PK 속성이 늘어나는 것은 본질식별자의 단점이다.
  • 복합 PK로 조인 조건이 복잡해지는 것도 본질식별자 쪽 문제이다.
  • 업무 의미가 담긴 PK 값이 바뀌는 위험은 본질식별자에 해당한다.
문제 11
SQL 명령어를 종류별로 묶었을 때 DCL(Data Control Language)에 해당하는 것은?
1COMMIT, ROLLBACK
2INSERT, MERGE
3GRANT, REVOKE
4CREATE, ALTER
정답 및 해설

DCL은 사용자에게 권한을 부여하고 회수하는 명령어로 GRANT·REVOKE가 해당한다.

SQL은 데이터 조작(DML), 구조 정의(DDL), 권한 제어(DCL), 트랜잭션 제어(TCL)로 나뉜다.

  • COMMIT·ROLLBACK은 트랜잭션을 확정·취소하는 TCL이다.
  • CREATE·ALTER는 객체 구조를 정의·변경하는 DDL이다.
  • INSERT·MERGE는 데이터를 조작하는 DML이다.
문제 12
SELECT 절의 표현에 대한 설명으로 적절하지 않은 것은?
1+, -가 *, /보다 먼저 계산된다
2DISTINCT는 열 조합 전체로 중복을 없앤다
3Oracle은 ||로 문자열을 연결한다
4공백이 든 별칭은 큰따옴표로 감싼다
정답 및 해설

산술 연산은 곱셈·나눗셈이 덧셈·뺄셈보다 먼저 계산되므로, 순서를 바꾸려면 괄호를 써야 한다.

예를 들어 100 + 20 * 3은 160이고 (100 + 20) * 3은 360이며, 우선순위가 같으면 왼쪽부터 계산한다.

  • DISTINCT는 SELECT 목록 전체 조합이 같은 행만 하나로 줄인다.
  • 공백이나 특수문자가 든 별칭은 큰따옴표로 감싼다.
  • Oracle은 ||, SQL Server는 +로 문자열을 잇는다.
문제 13
SELECT 문의 논리적 처리 순서에서 HAVING 절 바로 다음에 처리되는 절은?
1GROUP BY 절
2SELECT 절
3ORDER BY 절
4WHERE 절
정답 및 해설

논리적 처리 순서는 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY이므로 HAVING 다음은 SELECT 절이다.

SELECT가 ORDER BY보다 먼저 처리되기 때문에 ORDER BY에서는 SELECT 별칭을 쓸 수 있지만 WHERE·HAVING에서는 쓸 수 없다.

  • ORDER BY는 SELECT 다음, 맨 마지막에 처리된다.
  • GROUP BY는 HAVING보다 먼저 행을 그룹으로 묶는다.
  • WHERE는 FROM 직후, 그룹화 전에 행을 거른다.
문제 14
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[상품]

상품코드가격
KR-100115480
US-229950
JP-3051205
SELECT LPAD(상품코드, 6, '#') AS 코드,
       ROUND(가격, -2) AS 반올림,
       MOD(가격, 100) AS 나머지
  FROM 상품
 ORDER BY 가격 DESC;
1
코드반올림나머지
KR-1001540080
#US-22990050
JP-30512005
2
코드반올림나머지
KR-1001550080
#US-221000050
JP-30512005
3
코드반올림나머지
KR-10011550080
#US-221000050
JP-30512005
4
코드반올림나머지
KR-1001550080
US-22#1000050
JP-30512005
정답 및 해설

LPAD는 원본이 지정 길이보다 길면 잘라서 KR-1001이 KR-100이 되고, ROUND(가격, -2)는 십의 자리에서 반올림해 9950을 10000으로 만든다.

MOD(가격, 100)은 100으로 나눈 나머지라 80·50·5가 되며, 행은 가격 내림차순으로 정렬된다.

  • KR-1001을 그대로 둔 표는 LPAD의 잘림을 놓쳤다.
  • 15400·9900은 반올림이 아니라 TRUNC로 버린 결과이다.
  • US-22#은 오른쪽을 채우는 RPAD의 결과이다.
문제 15
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[예약]

예약번호인원할인율
14(null)
2210
3(null)0
435
SELECT 예약번호, NVL(인원, 1) AS 인원수,
       NVL2(할인율, '할인', '정가') AS 구분,
       NULLIF(할인율, 0) AS 할인
  FROM 예약
 ORDER BY 예약번호;
1
예약번호인원수구분할인
14정가(null)
22할인10
31할인(null)
43할인5
2
예약번호인원수구분할인
14정가(null)
22할인10
31할인0
43할인5
3
예약번호인원수구분할인
14정가0
22할인10
31할인(null)
43할인5
4
예약번호인원수구분할인
14정가(null)
22할인10
31정가(null)
43할인5
정답 및 해설

NVL2는 0도 NULL이 아닌 값으로 보므로 예약번호 3의 구분은 '할인'이고, NULLIF(할인율, 0)은 두 값이 같으면 NULL을 돌려주어 그 행의 할인이 NULL이 된다.

NVL(인원, 1)은 인원이 NULL인 예약번호 3만 1로 바꾸며, 할인율이 NULL인 예약번호 1은 NULLIF 결과도 NULL로 남는다.

  • 예약번호 3을 '정가'로 둔 표는 0을 NULL로 착각했다.
  • 예약번호 3의 할인을 0으로 둔 표는 NULLIF의 동작을 놓쳤다.
  • 예약번호 1의 할인을 0으로 둔 표는 NULLIF가 NULL을 0으로 바꾼다고 보았다.
문제 16
Oracle 기준으로 다음 결과를 얻기 위해 ㉠에 공통으로 들어갈 식으로 옳은 것은?

[주문]

주문번호고객번호주문일자금액
1102026-03-0530000
2112026-03-2812000
3102026-03-3145000
4122026-04-308000
5112026-05-0120000
6132026-05-3115000
SELECT ( ㉠ ) AS 주문월, COUNT(*) AS 건수, SUM(금액) AS 합계
  FROM 주문
 GROUP BY ( ㉠ )
 ORDER BY 주문월;
주문월건수합계
2026-03387000
2026-0418000
2026-05235000
1TO_DATE(주문일자, 'MM')
2TO_CHAR(주문일자, 'YYYY-MM')
3EXTRACT(MONTH FROM 주문일자)
4TRUNC(주문일자, 'MONTH')
정답 및 해설

결과의 주문월이 '2026-03' 같은 문자열이므로 날짜를 지정 형식의 문자로 바꾸는 TO_CHAR(날짜, 'YYYY-MM')가 들어가야 한다.

같은 식으로 GROUP BY 하면 3월 3건·4월 1건·5월 2건이 월별로 묶이고 금액이 합산된다.

  • EXTRACT(MONTH ...)는 연도 없이 3 같은 숫자 월만 돌려준다.
  • TRUNC(날짜, 'MONTH')는 2026-03-01 같은 월초 날짜를 돌려준다.
  • TO_DATE는 문자를 날짜로 바꾸는 함수라 결과가 문자열이 되지 않는다.
문제 17
다음 SQL을 실행한 결과로 옳은 것은?

[도서]

도서번호분류가격
1IT18000
2경제25000
3IT32000
4경제15000
5소설27000
6IT9000
7경제20000
SELECT 도서번호
  FROM 도서
 WHERE 분류 = 'IT' OR 분류 = '경제' AND 가격 >= 20000
 ORDER BY 도서번호;
1
도서번호
1
2
3
6
2
도서번호
1
2
3
6
7
3
도서번호
1
2
3
4
6
7
4
도서번호
2
3
7
정답 및 해설

AND가 OR보다 먼저 평가되므로 조건은 분류 = 'IT' OR (분류 = '경제' AND 가격 >= 20000)으로 해석된다.

IT 도서 1·3·6은 가격과 무관하게 모두 나오고, 경제 도서는 가격이 20000 이상인 2·7만 남아 도서번호 1, 2, 3, 6, 7이 조회된다.

  • 2, 3, 7만 남은 표는 OR를 먼저 묶은 (IT OR 경제) AND 가격 조건의 결과이다.
  • 7이 빠진 표는 경계값 20000을 포함하는 >=를 놓쳤다.
  • 4까지 나온 표는 가격 조건을 아예 무시한 결과이다.
문제 18
WHERE 절 연산자에 대한 설명으로 옳은 것은?
1IN 목록의 값들은 AND로 연결된다
2= NULL로 NULL인 행을 찾을 수 있다
3LIKE '_A%'는 A로 시작하는 값이다
4BETWEEN은 양 끝값을 포함한다
정답 및 해설

BETWEEN a AND b는 a 이상 b 이하, 즉 양 끝값을 포함하는 범위 조건이다.

LIKE의 _는 정확히 한 글자, %는 0글자 이상을 뜻하며, NULL 비교는 반드시 IS NULL로 한다.

  • '_A%'는 두 번째 글자가 A인 값을 찾는다.
  • = NULL 비교는 참이 되지 않아 어떤 행도 반환하지 않는다.
  • IN 목록은 OR로 연결된 등호 조건과 같다.
문제 19
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[수강]

학번강의코드점수
101DB80
102DB(null)
103DB100
101OS(null)
104OS(null)
105(null)70
SELECT 강의코드, COUNT(*) AS 인원, COUNT(점수) AS 응시,
       SUM(점수) AS 합계, AVG(점수) AS 평균
  FROM 수강
 GROUP BY 강의코드
 ORDER BY 강의코드;
1
강의코드인원응시합계평균
DB3218090
OS20(null)(null)
(null)117070
2
강의코드인원응시합계평균
DB3218060
OS20(null)(null)
(null)117070
3
강의코드인원응시합계평균
DB3218090
OS20(null)(null)
4
강의코드인원응시합계평균
DB3218090
OS2000
(null)117070
정답 및 해설

집계 함수는 NULL을 제외하므로 DB의 평균은 180/2=90이고, 점수가 모두 NULL인 OS는 COUNT(점수)가 0, SUM·AVG가 NULL이다.

그룹 기준 열의 NULL도 하나의 그룹이 되어 강의코드가 NULL인 행이 따로 나오고, Oracle 오름차순에서는 맨 뒤에 정렬된다.

  • DB 평균을 60으로 둔 표는 NULL을 0으로 보고 3으로 나눴다.
  • OS의 합계·평균을 0으로 둔 표는 값이 없는 SUM을 0으로 착각했다.
  • NULL 그룹을 뺀 표는 GROUP BY가 NULL 키도 묶는다는 점을 놓쳤다.
문제 20
다음 SQL을 실행한 결과로 옳은 것은?

[주문]

주문번호지점금액
1서울12000
2대전(null)
3서울8000
4(null)5000
5대전7000
SELECT COUNT(*) AS 건수, SUM(금액) AS 합계,
       COALESCE(MAX(금액), 0) AS 최대
  FROM 주문
 WHERE 지점 = '부산';
1
건수합계최대
(null)(null)0
2
건수합계최대
000
3
건수합계최대
4
건수합계최대
0(null)0
정답 및 해설

GROUP BY 없이 집계 함수만 쓰면 조건에 맞는 행이 없어도 결과는 항상 1행이며, 이때 COUNT(*)는 0, SUM은 NULL이다.

MAX도 NULL이지만 COALESCE가 0으로 바꾸어 최대는 0이 되고, 같은 쿼리에 GROUP BY를 붙이면 만들어질 그룹이 없어 0행이 된다.

  • 행이 없는 표는 GROUP BY가 있을 때의 동작이다.
  • 합계를 0으로 둔 표는 빈 집합의 SUM을 0으로 착각했다.
  • 건수를 NULL로 둔 표는 COUNT가 빈 집합에서 0을 돌려준다는 점을 놓쳤다.
문제 21
Oracle 기준으로 다음 SQL 중 오류가 발생하는 것을 모두 고른 것은?

[매출]

지점월금액
강남1120
강남280
잠실160
판교1200
판교230
㉠ SELECT 지점 FROM 매출 GROUP BY 지점 HAVING COUNT(*) >= 2;
㉡ SELECT 지점, SUM(금액) FROM 매출 WHERE SUM(금액) > 100 GROUP BY 지점;
㉢ SELECT 지점, 금액 FROM 매출 GROUP BY 지점;
㉣ SELECT COUNT(*) FROM 매출 HAVING COUNT(*) > 3;
1㉠, ㉢, ㉣
2㉡
3㉡, ㉢
4㉡, ㉣
정답 및 해설

집계 함수는 그룹이 만들어진 뒤 평가되므로 WHERE 절에 쓸 수 없고, GROUP BY에 없는 일반 열은 집계 없이 SELECT 절에 올 수 없다.

따라서 WHERE에 SUM을 쓴 ㉡과 그룹 기준이 아닌 금액을 그대로 조회한 ㉢이 오류를 일으킨다.

  • ㉠은 SELECT에 없는 집계를 HAVING에 써도 되므로 정상 실행된다.
  • ㉣은 GROUP BY 없이 테이블 전체를 한 그룹으로 보고 HAVING을 적용한다.
  • ㉡만 고르면 GROUP BY 열 제약을 어긴 ㉢을 놓친 것이다.
문제 22
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[사원]

사번이름부서코드급여
1김민D20300
2이준D10400
3박서D20250
4최유(null)350
5정하D10380
6한결D30280
SELECT 이름, 부서코드 AS 부서, 급여 * 12 AS 연봉
  FROM 사원
 ORDER BY 2 DESC, 연봉;
1
이름부서연봉
최유(null)4200
한결D303360
박서D203000
김민D203600
정하D104560
이준D104800
2
이름부서연봉
최유(null)4200
한결D303360
김민D203600
박서D203000
이준D104800
정하D104560
3
이름부서연봉
정하D104560
이준D104800
박서D203000
김민D203600
한결D303360
최유(null)4200
4
이름부서연봉
한결D303360
박서D203000
김민D203600
정하D104560
이준D104800
최유(null)4200
정답 및 해설

ORDER BY 2 DESC는 두 번째 열인 부서를 내림차순으로 정렬하며, Oracle은 NULL을 가장 큰 값으로 보아 DESC에서 NULL이 맨 앞에 온다.

DESC는 바로 앞 키에만 적용되므로 같은 부서 안에서는 별칭 연봉 기준 오름차순이 되어 D20은 박서·김민, D10은 정하·이준 순이다.

  • 최유를 맨 뒤에 둔 표는 NULL을 가장 작은 값으로 보았다.
  • 같은 부서에서 연봉이 큰 사원을 먼저 둔 표는 DESC가 모든 키에 적용된다고 보았다.
  • D10부터 나열한 표는 부서를 오름차순으로 정렬했다.
문제 23
다음 SQL을 실행한 결과로 옳은 것은?

[고객]

고객번호고객명누적금액
1가람50000
2나무100000
3다솜299999
4라온300000
5마음(null)
6보람1200000

[등급]

등급명하한상한
일반0100000
실버100000300000
골드3000001000000
SELECT C.고객명, G.등급명
  FROM 고객 C
  JOIN 등급 G
    ON C.누적금액 BETWEEN G.하한 AND G.상한
 ORDER BY C.고객번호, G.하한;
1
고객명등급명
가람일반
나무실버
다솜실버
라온골드
2
고객명등급명
가람일반
나무일반
나무실버
다솜실버
라온실버
라온골드
3
고객명등급명
가람일반
나무일반
다솜실버
라온실버
4
고객명등급명
가람일반
나무일반
나무실버
다솜실버
라온실버
라온골드
마음(null)
보람(null)
정답 및 해설

비등가 조인(Non-Equi Join)은 BETWEEN 조건을 만족하는 등급마다 행을 만들므로, 경계값 100000과 300000은 두 등급에 동시에 걸려 각각 2행이 된다.

50000·299999는 1행씩이고, 누적금액이 NULL인 마음과 범위를 벗어난 보람은 조건이 참이 아니어서 빠지므로 2+2+1+1=6행이다.

  • 나무를 실버에만 둔 표는 BETWEEN이 하한만 포함한다고 보았다.
  • 라온을 실버에만 둔 표는 BETWEEN이 상한만 포함한다고 보았다.
  • 마음·보람이 있는 표는 OUTER JOIN처럼 짝 없는 행을 남겼다.
문제 24
[고객] 테이블이 5행, [상품] 테이블이 8행일 때 다음 SQL의 결과 행 수는?
SELECT 고객.고객명, 상품.상품명
  FROM 고객, 상품;
18행
213행
340행
45행
정답 및 해설

FROM 절에 두 테이블을 나열하고 조인 조건을 주지 않으면 모든 행이 서로 짝지어지는 카티션 곱(Cartesian Product)이 되어 5×8=40행이 나온다.

ANSI 표준의 CROSS JOIN과 같은 결과이며, 조인 조건을 빠뜨리면 의도치 않게 행이 크게 늘어나므로 주의해야 한다.

  • 5행은 고객 테이블만 조회한 행 수이다.
  • 8행은 상품 테이블만 조회한 행 수이다.
  • 13행은 두 테이블을 UNION ALL로 이어 붙인 경우의 행 수이다.
문제 25
다음 SQL을 실행한 결과로 옳은 것은?

[부서]

부서코드부서명
D1기획
D2영업
D3개발
D4총무

[사원]

사번이름부서코드직급
1가윤D1대리
2나래D1과장
3다온D2과장
4라희D3대리
5마루D3대리
6사랑(null)대리
SELECT D.부서명, E.이름
  FROM 부서 D
  LEFT OUTER JOIN 사원 E
    ON D.부서코드 = E.부서코드
   AND E.직급 = '대리'
 ORDER BY D.부서코드, E.사번;
1
부서명이름
기획가윤
영업(null)
개발라희
개발마루
총무(null)
2
부서명이름
기획가윤
영업(null)
개발라희
개발마루
총무(null)
(null)사랑
3
부서명이름
기획가윤
개발라희
개발마루
4
부서명이름
기획가윤
기획나래
영업다온
개발라희
개발마루
총무(null)
정답 및 해설

ON 절의 직급 조건은 조인 대상만 제한하므로 LEFT OUTER JOIN의 왼쪽인 부서 4개는 모두 남고, 대리가 없는 영업·총무는 이름이 NULL로 나온다.

기획에는 대리인 가윤만, 개발에는 라희·마루가 붙어 모두 5행이며, 부서코드가 없는 사랑은 왼쪽 테이블에 짝이 없어 나오지 않는다.

  • 3행 표는 직급 조건을 WHERE에 둔 것처럼 NULL 행을 지웠다.
  • 나래·다온이 붙은 표는 ON 절의 직급 조건을 무시했다.
  • 부서명이 NULL인 행이 있는 표는 FULL OUTER JOIN의 결과이다.
문제 26
다음 SQL을 실행했을 때 결과 행 수와, 그중 주문번호가 NULL인 행의 수를 순서대로 나열한 것은?

[고객]

고객번호고객명
1김하늘
2박도윤
3이서준
4최유나

[주문]

주문번호고객번호금액상태
101130000완료
102115000취소
103220000취소
104312000완료
10538000완료
106(null)5000완료
SELECT C.고객명, O.주문번호
  FROM 고객 C LEFT OUTER JOIN 주문 O
    ON C.고객번호 = O.고객번호
   AND O.상태 = '완료'
 ORDER BY C.고객명, O.주문번호;
13, 0
24, 1
35, 2
46, 1
정답 및 해설

ON 절의 상태 조건은 조인 매칭 조건으로만 쓰이므로, 완료 주문이 없는 고객도 LEFT OUTER JOIN에 의해 주문번호 NULL 행으로 남아 5행이 된다.

김하늘 101, 이서준 104·105가 매칭되고 취소 주문만 있는 박도윤과 주문이 없는 최유나는 NULL 로 1행씩 보존된다. 고객번호가 NULL 인 106 주문은 기준 테이블에 짝이 없어 나오지 않는다.

  • 상태 조건을 WHERE 절에 둔 경우라야 NULL 행이 걸러져 3행이 된다.
  • 상태 조건을 무시하면 취소 주문까지 붙어 6행이 된다.
  • 박도윤을 빼는 것은 매칭 실패 행을 보존하는 외부 조인 규칙에 어긋난다.
문제 27
다음 [결과]가 나오도록 SQL의 ( ㉠ )에 들어갈 구문으로 옳은 것은?

[사원]

사원번호사원명부서코드지역
1강민서D1서울
2윤재희D2부산
3서도현D1부산
4임채원D3서울
5조하린(null)서울

[부서]

부서코드부서명지역
D1영업서울
D2개발부산
D3인사대전
SELECT 부서코드, E.사원명, D.부서명
  FROM 사원 E ( ㉠ )
 ORDER BY 부서코드, E.사원명;

[결과]

부서코드사원명부서명
D1강민서영업
D1서도현영업
D2윤재희개발
D3임채원인사
1NATURAL JOIN 부서 D
2CROSS JOIN 부서 D
3JOIN 부서 D ON E.부서코드 = D.부서코드
4JOIN 부서 D USING (부서코드)
정답 및 해설

USING (부서코드)는 지정한 열만 등가 조인하고 그 열을 하나로 합쳐 주므로, 접두어 없는 부서코드를 SELECT·ORDER BY 에 쓸 수 있다.

부서코드만으로 묶이면 서도현(부산)도 D1 영업과 연결되어 4행이 된다. 부서코드가 NULL 인 조하린은 등가 조건을 만족하지 못해 빠진다.

  • NATURAL JOIN 은 동명 열인 지역까지 비교해 강민서·윤재희 2행만 남는다.
  • ON 조인은 양쪽 부서코드가 모두 남아 접두어 없는 부서코드가 모호하다는 오류가 난다.
  • CROSS JOIN 도 부서코드가 두 테이블에 있어 같은 모호성 오류가 난다.
문제 28
다음 SQL의 실행 결과에서 건수와 최저가를 순서대로 나열한 것은?

[상품]

상품코드분류가격
P1A3000
P2A5000
P3B2000
P4B4000
P5C4500
P6C1500
SELECT COUNT(*) AS 건수, MIN(가격) AS 최저가
  FROM 상품
 WHERE 가격 > ALL (SELECT 가격
                     FROM 상품
                    WHERE 분류 = 'B');
13, 4000
22, 4500
32, 2000
44, 3000
정답 및 해설

> ALL은 서브쿼리가 돌려준 모든 값보다 커야 하므로 B 분류 가격 2000·4000 중 최댓값 4000을 넘는 행만 남는다.

4000을 넘는 상품은 P2(5000)와 P5(4500) 두 행이므로 건수는 2, 최저가는 4500이다.

  • 4건·3000은 최솟값 2000만 넘으면 되는 ANY 로 읽은 결과다.
  • 3건·4000은 같은 값도 포함하는 >= ALL 로 읽은 결과다.
  • 2건·2000은 서브쿼리 값과 같은 행을 고르는 IN 의 결과다.
문제 29
각 강의에서 그 강의 평균 점수를 넘는 수강 행만 다음 [결과]처럼 조회하려 한다. ( ㉠ )에 들어갈 조건으로 옳은 것은?

[수강]

학생번호강의코드점수
S1DB80
S2DB60
S3DB70
S1OS90
S2OS50
S4OS85
S3NW62
S4NW58
SELECT A.학생번호, A.강의코드, A.점수
  FROM 수강 A
 WHERE A.점수 > (SELECT AVG(B.점수)
                   FROM 수강 B
                  WHERE ( ㉠ ))
 ORDER BY A.강의코드, A.학생번호;

[결과]

학생번호강의코드점수
S1DB80
S3NW62
S1OS90
S4OS85
1B.학생번호 = A.학생번호
2A.강의코드 IS NOT NULL
3B.강의코드 = A.강의코드
4B.점수 >= A.점수
정답 및 해설

바깥 행의 강의코드로 서브쿼리를 묶는 연관 서브쿼리 조건 B.강의코드 = A.강의코드를 써야 행마다 그 강의의 평균과 비교한다.

DB 평균 70, OS 평균 75, NW 평균 60이므로 S1(DB 80), S3(NW 62), S1(OS 90), S4(OS 85) 4행이 남고 평균과 같은 S3(DB 70)은 빠진다.

  • 학생번호 로 묶으면 학생별 평균과 비교해 S2 의 DB 60 같은 행이 섞인다.
  • 자기 점수 이상인 점수의 평균은 자기 점수 미만일 수 없어 결과가 0행이다.
  • 바깥 열의 NULL 여부만 보면 전체 평균 69.375 와 비교하게 되어 S3 의 DB 70 이 들어온다.
문제 30
서브쿼리와 뷰(View)에 대한 설명으로 적절하지 않은 것은?
1인라인 뷰는 FROM 절에 쓰는 서브쿼리다
2스칼라 서브쿼리는 값 하나만 반환해야 한다
3뷰는 조회 결과 데이터를 따로 저장한다
4뷰로 테이블 구조 변경의 영향을 줄인다
정답 및 해설

뷰는 SELECT 문 정의만 저장하는 가상 테이블이고, 조회할 때마다 기반 테이블에서 데이터를 가져오므로 결과를 따로 저장하지 않는다.

결과를 물리적으로 저장하는 것은 구체화 뷰(Materialized View) 같은 별도 객체의 특징이다.

  • 스칼라 서브쿼리는 한 행 한 열의 값 하나를 돌려주어야 한다.
  • FROM 절 서브쿼리를 인라인 뷰라 부른다.
  • 뷰는 논리적 독립성을 주어 기반 구조 변경의 영향을 줄인다.
문제 31
다음 ㉠, ㉡ SQL의 결과 행 수를 순서대로 나열한 것은?

[온라인주문]

고객번호
1
2
2
3
(null)

[매장주문]

고객번호
3
4
4
(null)
㉠ SELECT 고객번호 FROM 온라인주문
   UNION
   SELECT 고객번호 FROM 매장주문;

㉡ SELECT 고객번호 FROM 온라인주문
   UNION ALL
   SELECT 고객번호 FROM 매장주문;
15, 9
27, 9
34, 7
44, 9
정답 및 해설

UNION은 두 결과를 합친 뒤 전체 중복을 제거하므로 1, 2, 3, 4, NULL 의 5행이고, UNION ALL 은 중복을 그대로 두어 5+4=9행이다.

집합 연산의 중복 판정에서 NULL 은 서로 같은 값으로 취급되어 한 행으로 남는다.

  • 4행은 NULL 을 결과에서 빼 버린 계산이다.
  • 7행은 두 테이블에 걸친 중복만 지우고 한 테이블 안의 2·4 중복을 남긴 계산이다.
  • UNION ALL 도 NULL 행을 지우지 않으므로 7행이 될 수 없다.
문제 32
다음 SQL의 [집합 연산자] 자리에 연산자를 바꿔 넣어 실행한 결과에 대한 설명으로 옳은 것은? (MINUS 는 Oracle 의 차집합 연산자로 EXCEPT 와 같다)

[봄학기]

학번
10
20
20
30
(null)

[가을학기]

학번
20
40
(null)
SELECT 학번 FROM 봄학기
[집합 연산자]
SELECT 학번 FROM 가을학기;
1MINUS 결과는 3행이다
2INTERSECT 결과는 2행이다
3UNION 결과에 NULL 행은 없다
4UNION ALL 결과는 7행이다
정답 및 해설

INTERSECT는 양쪽에 모두 있는 값을 중복 없이 돌려주는데, 집합 연산은 NULL 을 같은 값으로 비교하므로 20과 NULL 의 2행이 된다.

MINUS 는 봄학기에만 있는 10, 30을 중복 제거해 돌려준다.

  • MINUS 결과는 20의 중복과 무관하게 10·30 의 2행이다.
  • UNION 결과에는 NULL 이 한 행 포함된다.
  • UNION ALL 은 5행과 3행을 그대로 이어 8행이다.
문제 33
다음 SQL의 결과 행 수는?

[매출]

지점분기금액
강남Q1100
강남Q2200
강남Q150
판교Q1300
성수Q280
성수Q3120
SELECT 지점, 분기, SUM(금액) AS 합계
  FROM 매출
 GROUP BY ROLLUP(지점, 분기)
 ORDER BY 지점, 분기;
19행
26행
312행
48행
정답 및 해설

ROLLUP(지점, 분기)는 (지점, 분기) 그룹, 지점별 소계, 전체 총계를 차례로 만든다.

(지점, 분기) 조합은 강남 Q1·Q2, 판교 Q1, 성수 Q2·Q3 의 5행이고 강남 Q1 두 건은 한 행으로 합쳐진다. 여기에 지점 소계 3행과 총계 1행을 더해 9행이다.

  • 8행은 마지막 총계 행을 빠뜨린 계산이다.
  • 12행은 분기별 소계까지 만드는 CUBE 의 결과다.
  • 6행은 지점 소계 없이 총계만 더한 계산이다.
문제 34
다음 SQL의 결과에서 객실유형 열이 NULL 로 표시되는 행은 모두 몇 개인가?

[예약]

지점객실유형인원
서울스탠다드2
서울디럭스3
서울스탠다드1
부산디럭스2
부산(null)4
제주스탠다드2
SELECT 지점, 객실유형, SUM(인원) AS 합계
  FROM 예약
 GROUP BY CUBE(지점, 객실유형);
14개
26개
33개
45개
정답 및 해설

CUBE는 (지점, 객실유형)·지점·객실유형·전체의 네 수준을 모두 만들며, 객실유형이 NULL 로 보이는 행은 지점 소계, 총계, 그리고 원래 NULL 값을 가진 그룹이다.

지점 소계 3행과 총계 1행에 원본 NULL 인 부산 상세 행 1행, 객실유형별 소계 중 NULL 그룹 1행이 더해져 6개다.

  • 4개는 원본 데이터의 NULL 그룹 두 행을 모두 놓친 계산이다.
  • 5개는 객실유형별 소계에도 NULL 그룹이 생기는 점을 놓친 계산이다.
  • 3개는 지점 소계만 센 계산으로 총계를 빠뜨렸다.
문제 35
다음 [결과]가 나오도록 ( ㉠ )에 들어갈 구문으로 옳은 것은?

[판매]

지점상품수량
강남커피3
강남라떼2
판교커피4
판교(null)1
성수라떼6
SELECT 지점, 상품,
       GROUPING(지점) AS G1,
       GROUPING(상품) AS G2,
       SUM(수량) AS 합계
  FROM 판매
 GROUP BY ( ㉠ )
 ORDER BY G1, 지점, 상품;

[결과]

지점상품G1G2합계
강남(null)015
성수(null)016
판교(null)015
(null)라떼108
(null)커피107
(null)(null)101
1ROLLUP (지점, 상품)
2지점, 상품
3GROUPING SETS (지점, 상품)
4CUBE (지점, 상품)
정답 및 해설

결과에는 지점별 합계와 상품별 합계만 있고 상세 행과 총계가 없으므로 GROUPING SETS (지점, 상품)이다.

상품별 집계에서 지점이 집계로 사라진 행은 G1=1 이고, 판교의 원본 NULL 상품 그룹은 GROUPING 값이 0이라 집계 NULL 과 구분된다.

  • ROLLUP 은 지점·상품 상세 행과 총계를 함께 만든다.
  • CUBE 는 상세 행, 두 소계, 총계를 모두 만든다.
  • 단순 GROUP BY 는 상세 행만 만들고 G1·G2 가 모두 0이다.
문제 36
다음 SQL의 결과로 나오는 RNK, DRNK, RN 값을 순서대로 나열한 것은?

[게시글]

글번호조회수
A190
A2120
A390
A4150
A5120
A660
SELECT RNK, DRNK, RN
  FROM (SELECT 글번호,
               RANK() OVER (ORDER BY 조회수 DESC) AS RNK,
               DENSE_RANK() OVER (ORDER BY 조회수 DESC) AS DRNK,
               ROW_NUMBER() OVER (ORDER BY 조회수 DESC, 글번호) AS RN
          FROM 게시글) T
 WHERE 글번호 = 'A3'
 ORDER BY RN;
13, 3, 5
24, 3, 4
34, 4, 5
44, 3, 5
정답 및 해설

조회수 내림차순은 150, 120, 120, 90, 90, 60 이고 A3 은 90 동점 그룹이므로 RANK는 앞선 3행을 건너뛴 4, DENSE_RANK는 세 번째 값이라 3이다.

ROW_NUMBER 는 동점을 글번호로 다시 정렬해 A1 이 4, A3 이 5를 받는다.

  • RANK 를 3으로 보는 것은 DENSE_RANK 처럼 순위를 이어 붙인 것이다.
  • DRNK 를 4로 보는 것은 DENSE_RANK 도 순위를 건너뛴다고 본 것이다.
  • RN 을 4로 보는 것은 동점 안 정렬 기준인 글번호를 무시한 것이다.
문제 37
다음 SQL의 결과에서 누적 열 값을 위에서부터 차례로 나열한 것은?

[일매출]

지점일자금액
강남2026-03-0110
강남2026-03-0220
강남2026-03-025
강남2026-03-037
판교2026-03-0130
판교2026-03-0310
SELECT 지점, 일자, 금액,
       SUM(금액) OVER (PARTITION BY 지점
                       ORDER BY 일자) AS 누적
  FROM 일매출
 ORDER BY 지점, 일자, 금액;
110, 35, 35, 42, 30, 40
210, 15, 35, 42, 30, 40
310, 35, 35, 42, 72, 82
440, 65, 65, 82, 40, 82
정답 및 해설

윈도우 절 없이 ORDER BY 만 주면 기본 프레임이 RANGE UNBOUNDED PRECEDING이라, 강남 3월 2일 두 행은 같은 일자 전체를 포함한 35를 함께 받는다.

강남은 10, 35, 35, 42 로 누적되고 PARTITION BY 지점 때문에 판교에서 다시 시작해 30, 40 이 된다.

  • 10, 15 로 이어지는 값은 행 단위 ROWS 프레임으로 계산한 것이다.
  • 40, 65 로 시작하는 값은 지점 구분 없이 일자로만 누적한 것이다.
  • 판교가 72, 82 가 되는 것은 파티션에서 누적이 초기화되는 점을 놓친 것이다.
문제 38
다음 [결과]가 나오도록 ( ㉠ )에 들어갈 함수로 옳은 것은?

[지점주문]

지점일자금액
강남2026-04-01100
강남2026-04-02300
강남2026-04-03200
판교2026-04-01500
판교2026-04-02400
SELECT 지점, 일자, 금액,
       ( ㉠ ) OVER (PARTITION BY 지점
                    ORDER BY 일자) AS 비교값
  FROM 지점주문
 ORDER BY 지점, 일자;

[결과]

지점일자금액비교값
강남2026-04-01100(null)
강남2026-04-02300100
강남2026-04-03200300
판교2026-04-01500(null)
판교2026-04-02400500
1LEAD(금액, 1, 0)
2LAG(금액)
3FIRST_VALUE(금액)
4MAX(금액)
정답 및 해설

결과의 비교값은 같은 지점에서 바로 앞 일자의 금액이고 지점별 첫 행이 NULL 이므로 LAG(금액)이다.

강남은 NULL, 100, 300, 판교는 NULL, 500 이 되어 PARTITION BY 경계에서 이전 값이 끊긴다.

  • LEAD 는 다음 행 값을 가져와 강남이 300, 200, 0 이 된다.
  • FIRST_VALUE 는 기본 프레임의 첫 행이라 강남이 모두 100 이다.
  • MAX 는 누적 최댓값이라 강남이 100, 300, 300 이 된다.
문제 39
다음 SQL의 결과로 나오는 조와 백분위 값을 순서대로 나열한 것은?

[영업실적]

사원명실적
가람95
나래88
다온81
라희74
마루67
바다60
SELECT 조, 백분위
  FROM (SELECT 사원명,
               NTILE(4) OVER (ORDER BY 실적 DESC) AS 조,
               PERCENT_RANK() OVER (ORDER BY 실적 DESC) AS 백분위
          FROM 영업실적) T
 WHERE 사원명 = '마루'
 ORDER BY 조;
14, 0.8
23, 0.8
34, 0.83
43, 0.83
정답 및 해설

6행을 NTILE(4)로 나누면 나머지 2행을 앞 그룹부터 1개씩 더 주어 2, 2, 1, 1행이 되므로 다섯 번째인 마루는 3조다.

PERCENT_RANK는 (순위-1)/(전체 행 수-1)이므로 순위 5인 마루는 4/5 = 0.8 이다.

  • 4조는 나머지 행을 뒤쪽 그룹에 몰아 1, 1, 2, 3, 4, 4 로 나눈 것이다.
  • 0.83 은 순위를 전체 행 수로 나눈 CUME_DIST 식 계산이다.
  • 4조와 0.83 은 두 계산을 모두 잘못 적용한 값이다.
문제 40
Oracle 에서 다음 SQL을 실행했을 때 결과의 상품명을 출력 순서대로 나열한 것은? (상품판매 테이블은 표의 순서대로 입력되었다)

[상품판매]

상품명판매량
노트북120
스피커180
키보드(null)
마우스300
책상90
모니터250
SELECT 상품명, 판매량
  FROM (SELECT 상품명, 판매량
          FROM 상품판매
         ORDER BY 판매량 DESC, 상품명)
 WHERE ROWNUM <= 3;
1노트북, 스피커, 키보드
2책상, 노트북, 스피커
3마우스, 모니터, 스피커
4키보드, 마우스, 모니터
정답 및 해설

인라인 뷰에서 먼저 정렬한 뒤 ROWNUM을 매기므로 정렬 순서의 앞 3행이 나오는데, Oracle 은 NULL 을 최댓값으로 취급해 DESC 정렬 맨 앞에 둔다.

그래서 판매량이 NULL 인 키보드가 첫 행이 되고 마우스(300), 모니터(250)가 뒤따른다.

  • 마우스부터 시작하는 것은 DESC 에서도 NULL 이 뒤로 간다고 본 것이다.
  • 입력 순서 앞 3건이 나오는 것은 정렬 전에 ROWNUM 을 매기는 경우다.
  • 책상부터 시작하는 것은 오름차순 정렬로 잘못 읽은 것이다.
문제 41
SQL Server 에서 실행할 때 오류가 발생하는 SQL은? (상품 테이블에 상품명, 판매량 열이 있다)
1SELECT TOP(50) PERCENT 상품명 FROM 상품
2SELECT 상품명 FROM 상품 ORDER BY 1 OFFSET 2 ROWS
3SELECT TOP(2) 상품명 FROM 상품 ORDER BY 판매량 DESC
4SELECT TOP(3) WITH TIES 상품명, 판매량 FROM 상품
정답 및 해설

WITH TIES는 마지막 순위와 같은 값을 가진 행을 함께 돌려주는 옵션이라 동점 기준이 되는 ORDER BY 절이 반드시 있어야 하며, 없으면 오류가 난다.

TOP 만 단독으로 쓰거나 PERCENT 를 붙인 경우는 ORDER BY 없이도 실행되며 다만 어떤 행이 나올지 보장되지 않는다.

  • TOP(2)와 ORDER BY 를 함께 쓴 상위 2건 조회는 정상이다.
  • TOP(50) PERCENT 는 전체의 절반 행을 돌려주는 정상 구문이다.
  • ORDER BY 뒤 OFFSET 만 쓴 구문은 앞 2행을 건너뛰는 정상 구문이다.
문제 42
Oracle 에서 다음 SQL을 실행했을 때 결과의 이름을 단계 순서대로 나열한 것은?

[직원]

사번이름상사사번
1한서진(null)
2오지훈1
3정다인1
4배수아2
5노태윤4
6문가은4
7유하람3
SELECT LEVEL AS 단계, 이름
  FROM 직원
 START WITH 사번 = 4
CONNECT BY PRIOR 상사사번 = 사번
 ORDER BY 단계;
1배수아, 노태윤, 문가은
2배수아, 오지훈
3배수아, 오지훈, 한서진
4한서진, 오지훈, 배수아
정답 및 해설

PRIOR 상사사번 = 사번은 이전 행의 상사사번을 사번으로 갖는 행, 곧 상사 쪽으로 올라가는 역방향 전개다.

시작 행 배수아가 LEVEL 1이고 그 상사 오지훈이 2, 루트 한서진이 3이 되며, 루트의 상사사번이 NULL 이라 전개가 끝난다.

  • 부하 노태윤·문가은으로 내려가는 것은 PRIOR 사번 = 상사사번 인 순방향이다.
  • 한서진을 1단계로 보는 것은 LEVEL 이 시작 행에서 1부터 매겨지는 점을 놓친 것이다.
  • 루트도 연결 조건을 만족해 포함되므로 오지훈에서 끝나지 않는다.
문제 43
Oracle 에서 다음 SQL을 실행한 결과에 대한 설명으로 옳은 것은?

[카테고리]

코드이름상위코드
C1가전(null)
C2컴퓨터C1
C3노트북C2
C4주방C1
C5도서(null)
SELECT 이름,
       CONNECT_BY_ROOT 이름 AS 루트,
       CONNECT_BY_ISLEAF AS 리프,
       SYS_CONNECT_BY_PATH(이름, '/') AS 경로
  FROM 카테고리
 START WITH 상위코드 IS NULL
CONNECT BY PRIOR 코드 = 상위코드;
1도서 행의 경로 값은 /도서 이다
2노트북 행의 루트 값은 컴퓨터이다
3주방 행의 리프 값은 0이다
4컴퓨터 행의 리프 값은 1이다
정답 및 해설

SYS_CONNECT_BY_PATH는 루트부터 현재 행까지 값을 구분자로 이어 붙이되 맨 앞에도 구분자를 두므로, 단독 루트인 도서 행의 경로는 /도서 이다.

CONNECT_BY_ROOT는 그 행이 속한 트리의 루트 값을, CONNECT_BY_ISLEAF 는 자식이 없으면 1, 있으면 0을 돌려준다.

  • 노트북의 루트는 시작 행인 가전이며 컴퓨터는 바로 위 상위일 뿐이다.
  • 주방은 하위 행이 없는 말단이라 리프 값이 1이다.
  • 컴퓨터는 하위에 노트북이 있어 리프 값이 0이다.
문제 44
Oracle 에서 [예약] 테이블에 다음 SQL 을 실행한 결과로 옳은 것은?

[예약]

예약번호객실요일인원
1A토2
2A일3
3A토1
4B토4
5C금2
6C금3
7D일2
SELECT *
  FROM (SELECT 객실, 요일, 인원 FROM 예약)
 PIVOT (SUM(인원)
        FOR 요일 IN ('토' AS 토, '일' AS 일))
 ORDER BY 객실;
1
객실토일
A33
B4(null)
D(null)2
2
객실토일
A33
B40
C00
D02
3
객실토일금
A33(null)
B4(null)(null)
C(null)(null)5
D(null)2(null)
4
객실토일
A33
B4(null)
C(null)(null)
D(null)2
정답 및 해설

PIVOT은 IN 목록에 적은 '토'·'일'만 열로 만들고, 인라인 뷰에 남은 객실로 묶으므로 객실 A·B·C·D 네 행이 나온다.

객실 C 는 금요일 예약뿐이라 두 피벗 열이 모두 NULL 인 행으로 남고, 값이 없는 칸은 SUM 대상이 없어 0 이 아닌 NULL 로 표시된다.

  • 객실 C 가 빠진 표는 IN 목록 밖 값만 가진 그룹이 사라진다고 본 것이다.
  • 빈 칸을 0 으로 채운 표는 집계 대상이 없는 SUM 이 0 을 돌려준다고 본 것이다.
  • 금 열이 생긴 표는 IN 목록에 없는 값도 열로 펼쳐진다고 본 것이다.
문제 45
Oracle 에서 다음 SQL을 실행했을 때 결과에 포함되는 아이디는? (대소문자 구분은 기본 설정을 따른다)

[회원]

아이디가입일
kim012026-01-05
lee72026-01-09
park1232026-02-11
Choi222026-02-20
han_092026-03-02
yoon992026-03-15
jo12x2026-03-28
SELECT 아이디
  FROM 회원
 WHERE REGEXP_LIKE(아이디, '^[a-z]+[0-9]{2}$')
 ORDER BY 아이디;
1han_09
2park123
3yoon99
4Choi22
정답 및 해설

패턴은 처음부터 소문자 1개 이상, 이어서 숫자 정확히 2개로 끝나야 하므로 yoon99 가 일치하고 결과는 kim01, yoon99 두 행이다.

REGEXP_LIKE 는 기본 설정에서 대소문자를 구분하며 ^ 와 $ 가 문자열 전체를 감싸 중간 일치를 허용하지 않는다.

  • park123 은 숫자가 3개라 $ 앞의 {2} 를 만족하지 못한다.
  • Choi22 는 첫 글자 C 가 대문자라 [a-z] 에 맞지 않는다.
  • han_09 는 밑줄이 문자 클래스에 없어 일치하지 않는다.
문제 46
다음 UPDATE 문을 실행했을 때 수정되는 행의 수는?

[재고]

상품코드수량
A5
B20
C(null)
D15
E30
UPDATE 재고
   SET 수량 = 수량 + 10
 WHERE 수량 < 20;
11건
23건
32건
44건
정답 및 해설

UPDATE 는 WHERE 조건이 참인 행만 바꾸며, 수량이 NULL 인 C 는 비교 결과가 UNKNOWN이라 대상에서 빠진다.

조건을 만족하는 행은 A(5)와 D(15)뿐이므로 2건이 수정되고, 20인 B 는 미만 조건의 경계라 제외된다.

  • 3건은 NULL 인 C 까지 조건을 만족한다고 본 계산이다.
  • 4건은 경계값 20과 NULL 을 모두 포함한 계산이다.
  • 1건은 A 만 조건에 맞는다고 본 계산으로 D 를 놓쳤다.
문제 47
빈 예약 테이블에 대해 Oracle 에서 다음 문장을 차례로 실행했다. 마지막 SELECT 결과로 나오는 예약번호는?
INSERT INTO 예약 VALUES (10, '하윤');
SAVEPOINT SP1;
INSERT INTO 예약 VALUES (20, '시우');
SAVEPOINT SP2;
DELETE FROM 예약 WHERE 예약번호 = 10;
ROLLBACK TO SAVEPOINT SP1;
INSERT INTO 예약 VALUES (30, '지아');
COMMIT;

SELECT 예약번호 FROM 예약 ORDER BY 예약번호;
110, 20, 30
230
310, 30
420, 30
정답 및 해설

ROLLBACK TO SAVEPOINT SP1은 SP1 이후의 작업만 취소하므로 20 입력과 10 삭제가 모두 되돌려지고, SP1 이전의 10 입력은 남는다.

이어서 30을 입력하고 COMMIT으로 확정하므로 10과 30이 남는다.

  • 10, 20, 30이 남는 것은 SP2 까지만 되돌려 20 입력이 살아 있다고 본 결과다.
  • 30만 남는 것은 20 입력은 취소되고 10 삭제는 그대로라고 본 것이다.
  • 20과 30이 남는 것은 롤백이 10 삭제를 되돌리지 않는다고 본 것이다.
문제 48
다음 테이블을 만든 뒤 ㉠~㉣을 각각 실행할 때 제약조건 위반으로 실패하는 것은?
CREATE TABLE 회원 (
  회원번호 INT PRIMARY KEY,
  이메일   VARCHAR(50) UNIQUE,
  이름     VARCHAR(20) NOT NULL,
  나이     INT CHECK (나이 >= 14)
);
INSERT INTO 회원 VALUES (1, 'a@mail.com', '서윤', 20);

㉠ INSERT INTO 회원 VALUES (2, NULL, '도하', 30);
㉡ INSERT INTO 회원 VALUES (3, 'b@mail.com', '이안', 14);
㉢ INSERT INTO 회원 VALUES (4, 'c@mail.com', NULL, 25);
㉣ INSERT INTO 회원 VALUES (5, 'd@mail.com', '나린', NULL);
1㉠
2㉢
3㉡
4㉣
정답 및 해설

이름 열에 NOT NULL 제약이 있으므로 이름에 NULL 을 넣는 ㉢은 실패한다.

UNIQUE 열에는 NULL 을 넣을 수 있고, CHECK 조건은 결과가 거짓일 때만 거부하므로 NULL 처럼 판단할 수 없는 값은 통과한다.

  • ㉠은 이메일이 NULL 이지만 UNIQUE 는 NULL 입력을 막지 않는다.
  • ㉡은 나이 14가 이상 조건의 경계값이라 CHECK 를 만족한다.
  • ㉣은 나이가 NULL 이라 CHECK 결과가 UNKNOWN 으로 통과된다.
문제 49
Oracle 에서 상품 테이블(상품명, 단가, 비고 열 보유)에 실행할 때 문법 오류가 발생하는 것은?
1ALTER TABLE 상품 DROP COLUMN 비고
2ALTER TABLE 상품 ADD (원산지 VARCHAR2(20))
3ALTER TABLE 상품 MODIFY (상품명 VARCHAR2(100))
4ALTER TABLE 상품 RENAME 단가 TO 판매가
정답 및 해설

Oracle 에서 열 이름을 바꾸려면 ALTER TABLE 상품 RENAME COLUMN 단가 TO 판매가처럼 RENAME COLUMN 키워드가 있어야 하므로 COLUMN 을 빠뜨린 구문은 오류다.

테이블 이름 변경은 RENAME 옛이름 TO 새이름 또는 ALTER TABLE … RENAME TO 로 쓴다.

  • ADD 는 괄호 안에 새 열 정의를 적어 열을 추가하는 정상 구문이다.
  • MODIFY 는 기존 열의 길이·타입을 바꾸는 Oracle 정상 구문이다.
  • DROP COLUMN 은 지정한 열을 삭제하는 정상 구문이다.
문제 50
Oracle 에서 다음 문장을 차례로 실행한 뒤의 상태로 옳은 것은?
-- 관리자
GRANT SELECT ON 주문 TO U1 WITH GRANT OPTION;
-- U1
GRANT SELECT ON 주문 TO U2;
-- 관리자
REVOKE SELECT ON 주문 FROM U1;
1U1, U2 모두 권한을 잃는다
2어느 쪽 권한도 회수되지 않는다
3U2 때문에 REVOKE 가 실패한다
4U1 만 권한을 잃는다
정답 및 해설

WITH GRANT OPTION으로 받은 객체 권한을 회수하면 그 사용자가 다른 사용자에게 넘겨준 권한까지 연쇄적으로 회수되므로 U1 과 U2 모두 SELECT 권한을 잃는다.

연쇄 회수가 일어나지 않는 것은 시스템 권한을 WITH ADMIN OPTION 으로 넘긴 경우다.

  • U1 만 잃는 것은 WITH ADMIN OPTION 의 동작과 혼동한 것이다.
  • 재부여한 권한이 있어도 REVOKE 는 실패하지 않는다.
  • REVOKE 를 실행했으므로 U1 의 권한은 확실히 회수된다.
SQLD SQL 개발자 실전 모의고사모두CBT · moducbt.com
SQL 개발자 기출유형 모의고사 1회
총 50문항 · 객관식 · 정답·해설 포함
문제 1
데이터 모델링의 유의점 중 비유연성(Inflexibility)에 해당하는 설명은?
1수정된 값과 안 된 값이 서로 어긋난다
2복잡한 현실을 핵심 위주로 단순화한다
3작은 업무 변화에도 모델을 크게 고친다
4같은 정보를 여러 엔터티에 반복 저장한다
정답 및 해설

비유연성은 데이터 정의를 프로세스와 분리하지 못해 작은 업무 변화에도 모델을 크게 고쳐야 하는 상태를 말한다.

모델링 유의점은 중복(Duplication)·비유연성·비일관성(Inconsistency) 세 가지이며, 단순화·추상화·명확화는 모델링의 특징에 해당한다.

  • 같은 정보를 여러 곳에 반복 저장하는 것은 중복이다.
  • 수정된 값과 그렇지 않은 값이 어긋나는 것은 비일관성이다.
  • 현실을 핵심 위주로 단순화하는 것은 유의점이 아니라 모델링의 특징이다.
문제 2
다음 ERD의 엔터티를 발생 시점에 따라 분류한 것으로 옳은 것은?

그림

1고객은 중심, 주문변경이력은 행위 엔터티
2고객·지점은 기본, 주문은 중심 엔터티
3지점은 행위, 주문은 기본 엔터티
4주문은 기본, 주문변경이력은 중심 엔터티
정답 및 해설

다른 엔터티에 의존하지 않고 독립적으로 생성되는 고객·지점은 기본 엔터티이고, 이들로부터 발생하는 업무의 중심인 주문은 중심 엔터티이다.

주문변경이력처럼 부모 엔터티로부터 발생하고 내용이 자주 바뀌거나 계속 누적되는 엔터티는 행위 엔터티로 분류한다.

  • 주문은 고객·지점으로부터 발생하므로 기본 엔터티가 아니다.
  • 고객은 독립적으로 생성되므로 중심이 아니라 기본 엔터티이다.
  • 지점은 행위가 아니라 기본 엔터티이고 주문은 중심 엔터티이다.
문제 3
[주문] 엔터티의 속성을 분류한 것으로 적절하지 않은 것은?
1배송주소 - 더 나눌 수 없는 단일 속성
2주문번호 - 식별용으로 만든 설계 속성
3주문일자 - 업무에서 나온 기본 속성
4총주문금액 - 계산으로 얻는 파생 속성
정답 및 해설

시·구·동·상세주소로 나눌 수 있는 배송주소는 복합 속성(Composite Attribute)이므로 단일 속성으로 본 분류가 잘못되었다.

속성은 특성에 따라 기본·설계·파생 속성으로, 분해 여부에 따라 단일·복합 속성으로, 값의 개수에 따라 단일값·다중값 속성으로 나뉜다.

  • 주문일자는 업무에서 바로 도출되는 기본 속성이다.
  • 일련번호인 주문번호는 식별을 위해 새로 만든 설계 속성이다.
  • 상세 금액을 합산해 얻는 총주문금액은 파생 속성이다.
문제 4
관계를 '각각의 고객은 때때로 여러 건의 주문을 한다'처럼 읽을 때, '때때로'를 결정하는 관계 표기 요소는?
1관계차수
2관계선택사양
3관계명
4식별/비식별 구분
정답 및 해설

'반드시/때때로'는 관계에 참여하는 쪽이 필수인지 선택인지를 나타내는 관계선택사양(Optionality)이 결정한다.

관계는 관계명(Membership)·관계차수(Cardinality)·관계선택사양으로 표기하며, '하나 또는 여러'는 차수에, '반드시·때때로'는 필수(|)·선택(○) 표기에 대응한다.

  • 관계명은 '주문한다'처럼 관계의 이름을 나타낸다.
  • 관계차수는 1:1·1:M처럼 참여하는 건수를 나타낸다.
  • 식별/비식별 구분은 부모 식별자를 상속하는 방식이다.
문제 5
다음 ERD에서 [수강] 엔터티의 주식별자에 대한 설명으로 옳은 것은?

그림

1두 부모 식별자로 이루어진 복합식별자다
2강의코드는 강의 엔터티의 보조식별자다
3학번은 수강이 스스로 만든 내부식별자다
4업무와 무관하게 만든 인조식별자다
정답 및 해설

수강의 주식별자는 학생과 강의로부터 식별 관계로 상속받은 학번·강의코드 두 속성으로 이루어진 복합식별자이다.

관계를 통해 다른 엔터티에서 받아 온 식별자는 외부식별자이며, 업무에 실제 존재하는 값이므로 본질식별자에 해당한다.

  • 학번은 학생에서 상속된 외부식별자로, 스스로 생성된 내부식별자가 아니다.
  • 강의코드는 강의 엔터티의 주식별자이다.
  • 순번처럼 임의로 만든 값이 아니므로 인조식별자가 아니다.
문제 6
제1정규형을 만족하는 엔터티를 제2정규형(2NF)으로 정규화할 때 제거하는 종속은?
1이행 함수 종속
2조인 종속
3다치 종속
4부분 함수 종속
정답 및 해설

주식별자 일부에만 종속되는 부분 함수 종속을 제거하는 단계는 제2정규형(2NF)이다.

예를 들어 (주문번호, 상품코드)가 주식별자인데 상품명이 상품코드에만 종속되면, 상품명을 상품 엔터티로 분리해야 한다.

  • 일반 속성 사이의 이행 함수 종속은 제3정규형에서 제거한다.
  • 다치 종속은 제4정규형에서 제거한다.
  • 조인 종속은 제5정규형에서 제거한다.
문제 7
다음 ERD를 바탕으로 고객명과 주문한 상품명을 함께 조회할 때, 조인에 대한 설명으로 옳은 것은?

그림

1주문과 주문상세는 주문번호로 조인한다
2상품은 주문과 상품코드로 조인한다
3고객과 상품은 고객번호로 바로 조인한다
4주문상세는 고객번호로 고객과 조인한다
정답 및 해설

주문상세는 주문과 식별 관계로 연결되어 주문번호를 상속받으므로, 두 테이블은 주문번호로 조인한다.

고객명과 상품명을 함께 얻으려면 고객→주문→주문상세→상품 순으로 관계마다 PK-FK 쌍을 하나씩, 모두 3개의 조인 조건으로 연결한다.

  • 고객과 상품 사이에는 직접 관계가 없어 공통 속성이 없다.
  • 주문상세에는 고객번호가 없어 주문을 거쳐야 고객과 연결된다.
  • 주문에는 상품코드가 없고 상품코드는 주문상세가 가진다.
문제 8
주문 1건을 등록할 때 주문과 주문상세가 반드시 함께 생성되어야 한다. 이를 데이터 모델에 표현하는 방법으로 가장 적절한 것은?
1상세를 주문의 다중값 속성으로 둔다
2두 엔터티를 별도 트랜잭션으로 나눈다
3주문상세 참여를 선택(○)으로 표기한다
4두 엔터티 관계를 양쪽 필수로 표기한다
정답 및 해설

주문과 주문상세가 한 단위로 함께 생성되어야 한다면 두 엔터티의 관계를 양쪽 필수로 표기해 하나의 트랜잭션으로 처리됨을 드러낸다.

이 표기는 주문 없는 상세나 상세 없는 주문이 생기지 않도록 두 INSERT를 한 트랜잭션으로 묶어야 한다는 것을 알려 준다.

  • 주문상세 참여를 선택으로 두면 상세 없는 주문을 허용하는 모델이 된다.
  • 별도 트랜잭션으로 나누면 한쪽만 저장되는 불일치가 생길 수 있다.
  • 상세를 다중값 속성으로 두면 제1정규형을 위반한다.
문제 9
다음 [직원] 테이블에 SQL을 실행했을 때 A, B, C, D 값을 순서대로 나열한 것은?

[직원]

사번이름급여수당
1윤서30060
2도윤250(null)
3하준4000
4시우350(null)
5지호20030
SELECT COUNT(*) AS A, COUNT(수당) AS B, AVG(수당) AS C,
       SUM(급여 + 수당) AS D
  FROM 직원;
15, 3, 18, 1590
25, 5, 18, 990
33, 3, 30, 990
45, 3, 30, 990
정답 및 해설

COUNT(수당)·AVG(수당)는 NULL을 제외하고 계산하고, 급여+수당처럼 NULL이 섞인 산술 연산은 결과가 NULL이 되어 SUM에서 빠진다.

A는 전체 5행, B는 0을 포함해 수당이 있는 3행, C는 (60+0+30)/3=30, D는 360+400+230=990이다.

  • 평균 18은 NULL을 0으로 보고 5행으로 나눈 값이다.
  • 1590은 NULL을 0으로 본 SUM(급여)+SUM(수당)의 값이다.
  • COUNT(*)는 NULL 여부와 관계없이 모든 행을 세므로 3이 아니다.
문제 10
본질식별자 대신 인조식별자(일련번호)를 주식별자로 쓸 때의 단점으로 옳은 것은?
1자식으로 갈수록 PK 속성 수가 늘어난다
2조인 조건이 여러 속성으로 복잡해진다
3업무 규칙이 바뀌면 PK 값을 고쳐야 한다
4같은 업무 데이터의 중복 입력을 막기 어렵다
정답 및 해설

인조식별자는 업무와 무관한 일련번호라서 본질 속성에 유니크 제약이 없으면 같은 데이터가 중복 입력될 수 있고, 이를 막으려면 추가 인덱스가 필요하다.

반대로 본질식별자는 업무 의미를 그대로 담아 정합성 확인에 유리하지만 PK가 길고 복잡해지기 쉽다.

  • 자식으로 내려갈수록 PK 속성이 늘어나는 것은 본질식별자의 단점이다.
  • 복합 PK로 조인 조건이 복잡해지는 것도 본질식별자 쪽 문제이다.
  • 업무 의미가 담긴 PK 값이 바뀌는 위험은 본질식별자에 해당한다.
문제 11
SQL 명령어를 종류별로 묶었을 때 DCL(Data Control Language)에 해당하는 것은?
1COMMIT, ROLLBACK
2INSERT, MERGE
3GRANT, REVOKE
4CREATE, ALTER
정답 및 해설

DCL은 사용자에게 권한을 부여하고 회수하는 명령어로 GRANT·REVOKE가 해당한다.

SQL은 데이터 조작(DML), 구조 정의(DDL), 권한 제어(DCL), 트랜잭션 제어(TCL)로 나뉜다.

  • COMMIT·ROLLBACK은 트랜잭션을 확정·취소하는 TCL이다.
  • CREATE·ALTER는 객체 구조를 정의·변경하는 DDL이다.
  • INSERT·MERGE는 데이터를 조작하는 DML이다.
문제 12
SELECT 절의 표현에 대한 설명으로 적절하지 않은 것은?
1+, -가 *, /보다 먼저 계산된다
2DISTINCT는 열 조합 전체로 중복을 없앤다
3Oracle은 ||로 문자열을 연결한다
4공백이 든 별칭은 큰따옴표로 감싼다
정답 및 해설

산술 연산은 곱셈·나눗셈이 덧셈·뺄셈보다 먼저 계산되므로, 순서를 바꾸려면 괄호를 써야 한다.

예를 들어 100 + 20 * 3은 160이고 (100 + 20) * 3은 360이며, 우선순위가 같으면 왼쪽부터 계산한다.

  • DISTINCT는 SELECT 목록 전체 조합이 같은 행만 하나로 줄인다.
  • 공백이나 특수문자가 든 별칭은 큰따옴표로 감싼다.
  • Oracle은 ||, SQL Server는 +로 문자열을 잇는다.
문제 13
SELECT 문의 논리적 처리 순서에서 HAVING 절 바로 다음에 처리되는 절은?
1GROUP BY 절
2SELECT 절
3ORDER BY 절
4WHERE 절
정답 및 해설

논리적 처리 순서는 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY이므로 HAVING 다음은 SELECT 절이다.

SELECT가 ORDER BY보다 먼저 처리되기 때문에 ORDER BY에서는 SELECT 별칭을 쓸 수 있지만 WHERE·HAVING에서는 쓸 수 없다.

  • ORDER BY는 SELECT 다음, 맨 마지막에 처리된다.
  • GROUP BY는 HAVING보다 먼저 행을 그룹으로 묶는다.
  • WHERE는 FROM 직후, 그룹화 전에 행을 거른다.
문제 14
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[상품]

상품코드가격
KR-100115480
US-229950
JP-3051205
SELECT LPAD(상품코드, 6, '#') AS 코드,
       ROUND(가격, -2) AS 반올림,
       MOD(가격, 100) AS 나머지
  FROM 상품
 ORDER BY 가격 DESC;
1
코드반올림나머지
KR-1001540080
#US-22990050
JP-30512005
2
코드반올림나머지
KR-1001550080
#US-221000050
JP-30512005
3
코드반올림나머지
KR-10011550080
#US-221000050
JP-30512005
4
코드반올림나머지
KR-1001550080
US-22#1000050
JP-30512005
정답 및 해설

LPAD는 원본이 지정 길이보다 길면 잘라서 KR-1001이 KR-100이 되고, ROUND(가격, -2)는 십의 자리에서 반올림해 9950을 10000으로 만든다.

MOD(가격, 100)은 100으로 나눈 나머지라 80·50·5가 되며, 행은 가격 내림차순으로 정렬된다.

  • KR-1001을 그대로 둔 표는 LPAD의 잘림을 놓쳤다.
  • 15400·9900은 반올림이 아니라 TRUNC로 버린 결과이다.
  • US-22#은 오른쪽을 채우는 RPAD의 결과이다.
문제 15
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[예약]

예약번호인원할인율
14(null)
2210
3(null)0
435
SELECT 예약번호, NVL(인원, 1) AS 인원수,
       NVL2(할인율, '할인', '정가') AS 구분,
       NULLIF(할인율, 0) AS 할인
  FROM 예약
 ORDER BY 예약번호;
1
예약번호인원수구분할인
14정가(null)
22할인10
31할인(null)
43할인5
2
예약번호인원수구분할인
14정가(null)
22할인10
31할인0
43할인5
3
예약번호인원수구분할인
14정가0
22할인10
31할인(null)
43할인5
4
예약번호인원수구분할인
14정가(null)
22할인10
31정가(null)
43할인5
정답 및 해설

NVL2는 0도 NULL이 아닌 값으로 보므로 예약번호 3의 구분은 '할인'이고, NULLIF(할인율, 0)은 두 값이 같으면 NULL을 돌려주어 그 행의 할인이 NULL이 된다.

NVL(인원, 1)은 인원이 NULL인 예약번호 3만 1로 바꾸며, 할인율이 NULL인 예약번호 1은 NULLIF 결과도 NULL로 남는다.

  • 예약번호 3을 '정가'로 둔 표는 0을 NULL로 착각했다.
  • 예약번호 3의 할인을 0으로 둔 표는 NULLIF의 동작을 놓쳤다.
  • 예약번호 1의 할인을 0으로 둔 표는 NULLIF가 NULL을 0으로 바꾼다고 보았다.
문제 16
Oracle 기준으로 다음 결과를 얻기 위해 ㉠에 공통으로 들어갈 식으로 옳은 것은?

[주문]

주문번호고객번호주문일자금액
1102026-03-0530000
2112026-03-2812000
3102026-03-3145000
4122026-04-308000
5112026-05-0120000
6132026-05-3115000
SELECT ( ㉠ ) AS 주문월, COUNT(*) AS 건수, SUM(금액) AS 합계
  FROM 주문
 GROUP BY ( ㉠ )
 ORDER BY 주문월;
주문월건수합계
2026-03387000
2026-0418000
2026-05235000
1TO_DATE(주문일자, 'MM')
2TO_CHAR(주문일자, 'YYYY-MM')
3EXTRACT(MONTH FROM 주문일자)
4TRUNC(주문일자, 'MONTH')
정답 및 해설

결과의 주문월이 '2026-03' 같은 문자열이므로 날짜를 지정 형식의 문자로 바꾸는 TO_CHAR(날짜, 'YYYY-MM')가 들어가야 한다.

같은 식으로 GROUP BY 하면 3월 3건·4월 1건·5월 2건이 월별로 묶이고 금액이 합산된다.

  • EXTRACT(MONTH ...)는 연도 없이 3 같은 숫자 월만 돌려준다.
  • TRUNC(날짜, 'MONTH')는 2026-03-01 같은 월초 날짜를 돌려준다.
  • TO_DATE는 문자를 날짜로 바꾸는 함수라 결과가 문자열이 되지 않는다.
문제 17
다음 SQL을 실행한 결과로 옳은 것은?

[도서]

도서번호분류가격
1IT18000
2경제25000
3IT32000
4경제15000
5소설27000
6IT9000
7경제20000
SELECT 도서번호
  FROM 도서
 WHERE 분류 = 'IT' OR 분류 = '경제' AND 가격 >= 20000
 ORDER BY 도서번호;
1
도서번호
1
2
3
6
2
도서번호
1
2
3
6
7
3
도서번호
1
2
3
4
6
7
4
도서번호
2
3
7
정답 및 해설

AND가 OR보다 먼저 평가되므로 조건은 분류 = 'IT' OR (분류 = '경제' AND 가격 >= 20000)으로 해석된다.

IT 도서 1·3·6은 가격과 무관하게 모두 나오고, 경제 도서는 가격이 20000 이상인 2·7만 남아 도서번호 1, 2, 3, 6, 7이 조회된다.

  • 2, 3, 7만 남은 표는 OR를 먼저 묶은 (IT OR 경제) AND 가격 조건의 결과이다.
  • 7이 빠진 표는 경계값 20000을 포함하는 >=를 놓쳤다.
  • 4까지 나온 표는 가격 조건을 아예 무시한 결과이다.
문제 18
WHERE 절 연산자에 대한 설명으로 옳은 것은?
1IN 목록의 값들은 AND로 연결된다
2= NULL로 NULL인 행을 찾을 수 있다
3LIKE '_A%'는 A로 시작하는 값이다
4BETWEEN은 양 끝값을 포함한다
정답 및 해설

BETWEEN a AND b는 a 이상 b 이하, 즉 양 끝값을 포함하는 범위 조건이다.

LIKE의 _는 정확히 한 글자, %는 0글자 이상을 뜻하며, NULL 비교는 반드시 IS NULL로 한다.

  • '_A%'는 두 번째 글자가 A인 값을 찾는다.
  • = NULL 비교는 참이 되지 않아 어떤 행도 반환하지 않는다.
  • IN 목록은 OR로 연결된 등호 조건과 같다.
문제 19
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[수강]

학번강의코드점수
101DB80
102DB(null)
103DB100
101OS(null)
104OS(null)
105(null)70
SELECT 강의코드, COUNT(*) AS 인원, COUNT(점수) AS 응시,
       SUM(점수) AS 합계, AVG(점수) AS 평균
  FROM 수강
 GROUP BY 강의코드
 ORDER BY 강의코드;
1
강의코드인원응시합계평균
DB3218090
OS20(null)(null)
(null)117070
2
강의코드인원응시합계평균
DB3218060
OS20(null)(null)
(null)117070
3
강의코드인원응시합계평균
DB3218090
OS20(null)(null)
4
강의코드인원응시합계평균
DB3218090
OS2000
(null)117070
정답 및 해설

집계 함수는 NULL을 제외하므로 DB의 평균은 180/2=90이고, 점수가 모두 NULL인 OS는 COUNT(점수)가 0, SUM·AVG가 NULL이다.

그룹 기준 열의 NULL도 하나의 그룹이 되어 강의코드가 NULL인 행이 따로 나오고, Oracle 오름차순에서는 맨 뒤에 정렬된다.

  • DB 평균을 60으로 둔 표는 NULL을 0으로 보고 3으로 나눴다.
  • OS의 합계·평균을 0으로 둔 표는 값이 없는 SUM을 0으로 착각했다.
  • NULL 그룹을 뺀 표는 GROUP BY가 NULL 키도 묶는다는 점을 놓쳤다.
문제 20
다음 SQL을 실행한 결과로 옳은 것은?

[주문]

주문번호지점금액
1서울12000
2대전(null)
3서울8000
4(null)5000
5대전7000
SELECT COUNT(*) AS 건수, SUM(금액) AS 합계,
       COALESCE(MAX(금액), 0) AS 최대
  FROM 주문
 WHERE 지점 = '부산';
1
건수합계최대
(null)(null)0
2
건수합계최대
000
3
건수합계최대
4
건수합계최대
0(null)0
정답 및 해설

GROUP BY 없이 집계 함수만 쓰면 조건에 맞는 행이 없어도 결과는 항상 1행이며, 이때 COUNT(*)는 0, SUM은 NULL이다.

MAX도 NULL이지만 COALESCE가 0으로 바꾸어 최대는 0이 되고, 같은 쿼리에 GROUP BY를 붙이면 만들어질 그룹이 없어 0행이 된다.

  • 행이 없는 표는 GROUP BY가 있을 때의 동작이다.
  • 합계를 0으로 둔 표는 빈 집합의 SUM을 0으로 착각했다.
  • 건수를 NULL로 둔 표는 COUNT가 빈 집합에서 0을 돌려준다는 점을 놓쳤다.
문제 21
Oracle 기준으로 다음 SQL 중 오류가 발생하는 것을 모두 고른 것은?

[매출]

지점월금액
강남1120
강남280
잠실160
판교1200
판교230
㉠ SELECT 지점 FROM 매출 GROUP BY 지점 HAVING COUNT(*) >= 2;
㉡ SELECT 지점, SUM(금액) FROM 매출 WHERE SUM(금액) > 100 GROUP BY 지점;
㉢ SELECT 지점, 금액 FROM 매출 GROUP BY 지점;
㉣ SELECT COUNT(*) FROM 매출 HAVING COUNT(*) > 3;
1㉠, ㉢, ㉣
2㉡
3㉡, ㉢
4㉡, ㉣
정답 및 해설

집계 함수는 그룹이 만들어진 뒤 평가되므로 WHERE 절에 쓸 수 없고, GROUP BY에 없는 일반 열은 집계 없이 SELECT 절에 올 수 없다.

따라서 WHERE에 SUM을 쓴 ㉡과 그룹 기준이 아닌 금액을 그대로 조회한 ㉢이 오류를 일으킨다.

  • ㉠은 SELECT에 없는 집계를 HAVING에 써도 되므로 정상 실행된다.
  • ㉣은 GROUP BY 없이 테이블 전체를 한 그룹으로 보고 HAVING을 적용한다.
  • ㉡만 고르면 GROUP BY 열 제약을 어긴 ㉢을 놓친 것이다.
문제 22
Oracle 기준으로 다음 SQL을 실행한 결과로 옳은 것은?

[사원]

사번이름부서코드급여
1김민D20300
2이준D10400
3박서D20250
4최유(null)350
5정하D10380
6한결D30280
SELECT 이름, 부서코드 AS 부서, 급여 * 12 AS 연봉
  FROM 사원
 ORDER BY 2 DESC, 연봉;
1
이름부서연봉
최유(null)4200
한결D303360
박서D203000
김민D203600
정하D104560
이준D104800
2
이름부서연봉
최유(null)4200
한결D303360
김민D203600
박서D203000
이준D104800
정하D104560
3
이름부서연봉
정하D104560
이준D104800
박서D203000
김민D203600
한결D303360
최유(null)4200
4
이름부서연봉
한결D303360
박서D203000
김민D203600
정하D104560
이준D104800
최유(null)4200
정답 및 해설

ORDER BY 2 DESC는 두 번째 열인 부서를 내림차순으로 정렬하며, Oracle은 NULL을 가장 큰 값으로 보아 DESC에서 NULL이 맨 앞에 온다.

DESC는 바로 앞 키에만 적용되므로 같은 부서 안에서는 별칭 연봉 기준 오름차순이 되어 D20은 박서·김민, D10은 정하·이준 순이다.

  • 최유를 맨 뒤에 둔 표는 NULL을 가장 작은 값으로 보았다.
  • 같은 부서에서 연봉이 큰 사원을 먼저 둔 표는 DESC가 모든 키에 적용된다고 보았다.
  • D10부터 나열한 표는 부서를 오름차순으로 정렬했다.
문제 23
다음 SQL을 실행한 결과로 옳은 것은?

[고객]

고객번호고객명누적금액
1가람50000
2나무100000
3다솜299999
4라온300000
5마음(null)
6보람1200000

[등급]

등급명하한상한
일반0100000
실버100000300000
골드3000001000000
SELECT C.고객명, G.등급명
  FROM 고객 C
  JOIN 등급 G
    ON C.누적금액 BETWEEN G.하한 AND G.상한
 ORDER BY C.고객번호, G.하한;
1
고객명등급명
가람일반
나무실버
다솜실버
라온골드
2
고객명등급명
가람일반
나무일반
나무실버
다솜실버
라온실버
라온골드
3
고객명등급명
가람일반
나무일반
다솜실버
라온실버
4
고객명등급명
가람일반
나무일반
나무실버
다솜실버
라온실버
라온골드
마음(null)
보람(null)
정답 및 해설

비등가 조인(Non-Equi Join)은 BETWEEN 조건을 만족하는 등급마다 행을 만들므로, 경계값 100000과 300000은 두 등급에 동시에 걸려 각각 2행이 된다.

50000·299999는 1행씩이고, 누적금액이 NULL인 마음과 범위를 벗어난 보람은 조건이 참이 아니어서 빠지므로 2+2+1+1=6행이다.

  • 나무를 실버에만 둔 표는 BETWEEN이 하한만 포함한다고 보았다.
  • 라온을 실버에만 둔 표는 BETWEEN이 상한만 포함한다고 보았다.
  • 마음·보람이 있는 표는 OUTER JOIN처럼 짝 없는 행을 남겼다.
문제 24
[고객] 테이블이 5행, [상품] 테이블이 8행일 때 다음 SQL의 결과 행 수는?
SELECT 고객.고객명, 상품.상품명
  FROM 고객, 상품;
18행
213행
340행
45행
정답 및 해설

FROM 절에 두 테이블을 나열하고 조인 조건을 주지 않으면 모든 행이 서로 짝지어지는 카티션 곱(Cartesian Product)이 되어 5×8=40행이 나온다.

ANSI 표준의 CROSS JOIN과 같은 결과이며, 조인 조건을 빠뜨리면 의도치 않게 행이 크게 늘어나므로 주의해야 한다.

  • 5행은 고객 테이블만 조회한 행 수이다.
  • 8행은 상품 테이블만 조회한 행 수이다.
  • 13행은 두 테이블을 UNION ALL로 이어 붙인 경우의 행 수이다.
문제 25
다음 SQL을 실행한 결과로 옳은 것은?

[부서]

부서코드부서명
D1기획
D2영업
D3개발
D4총무

[사원]

사번이름부서코드직급
1가윤D1대리
2나래D1과장
3다온D2과장
4라희D3대리
5마루D3대리
6사랑(null)대리
SELECT D.부서명, E.이름
  FROM 부서 D
  LEFT OUTER JOIN 사원 E
    ON D.부서코드 = E.부서코드
   AND E.직급 = '대리'
 ORDER BY D.부서코드, E.사번;
1
부서명이름
기획가윤
영업(null)
개발라희
개발마루
총무(null)
2
부서명이름
기획가윤
영업(null)
개발라희
개발마루
총무(null)
(null)사랑
3
부서명이름
기획가윤
개발라희
개발마루
4
부서명이름
기획가윤
기획나래
영업다온
개발라희
개발마루
총무(null)
정답 및 해설

ON 절의 직급 조건은 조인 대상만 제한하므로 LEFT OUTER JOIN의 왼쪽인 부서 4개는 모두 남고, 대리가 없는 영업·총무는 이름이 NULL로 나온다.

기획에는 대리인 가윤만, 개발에는 라희·마루가 붙어 모두 5행이며, 부서코드가 없는 사랑은 왼쪽 테이블에 짝이 없어 나오지 않는다.

  • 3행 표는 직급 조건을 WHERE에 둔 것처럼 NULL 행을 지웠다.
  • 나래·다온이 붙은 표는 ON 절의 직급 조건을 무시했다.
  • 부서명이 NULL인 행이 있는 표는 FULL OUTER JOIN의 결과이다.
문제 26
다음 SQL을 실행했을 때 결과 행 수와, 그중 주문번호가 NULL인 행의 수를 순서대로 나열한 것은?

[고객]

고객번호고객명
1김하늘
2박도윤
3이서준
4최유나

[주문]

주문번호고객번호금액상태
101130000완료
102115000취소
103220000취소
104312000완료
10538000완료
106(null)5000완료
SELECT C.고객명, O.주문번호
  FROM 고객 C LEFT OUTER JOIN 주문 O
    ON C.고객번호 = O.고객번호
   AND O.상태 = '완료'
 ORDER BY C.고객명, O.주문번호;
13, 0
24, 1
35, 2
46, 1
정답 및 해설

ON 절의 상태 조건은 조인 매칭 조건으로만 쓰이므로, 완료 주문이 없는 고객도 LEFT OUTER JOIN에 의해 주문번호 NULL 행으로 남아 5행이 된다.

김하늘 101, 이서준 104·105가 매칭되고 취소 주문만 있는 박도윤과 주문이 없는 최유나는 NULL 로 1행씩 보존된다. 고객번호가 NULL 인 106 주문은 기준 테이블에 짝이 없어 나오지 않는다.

  • 상태 조건을 WHERE 절에 둔 경우라야 NULL 행이 걸러져 3행이 된다.
  • 상태 조건을 무시하면 취소 주문까지 붙어 6행이 된다.
  • 박도윤을 빼는 것은 매칭 실패 행을 보존하는 외부 조인 규칙에 어긋난다.
문제 27
다음 [결과]가 나오도록 SQL의 ( ㉠ )에 들어갈 구문으로 옳은 것은?

[사원]

사원번호사원명부서코드지역
1강민서D1서울
2윤재희D2부산
3서도현D1부산
4임채원D3서울
5조하린(null)서울

[부서]

부서코드부서명지역
D1영업서울
D2개발부산
D3인사대전
SELECT 부서코드, E.사원명, D.부서명
  FROM 사원 E ( ㉠ )
 ORDER BY 부서코드, E.사원명;

[결과]

부서코드사원명부서명
D1강민서영업
D1서도현영업
D2윤재희개발
D3임채원인사
1NATURAL JOIN 부서 D
2CROSS JOIN 부서 D
3JOIN 부서 D ON E.부서코드 = D.부서코드
4JOIN 부서 D USING (부서코드)
정답 및 해설

USING (부서코드)는 지정한 열만 등가 조인하고 그 열을 하나로 합쳐 주므로, 접두어 없는 부서코드를 SELECT·ORDER BY 에 쓸 수 있다.

부서코드만으로 묶이면 서도현(부산)도 D1 영업과 연결되어 4행이 된다. 부서코드가 NULL 인 조하린은 등가 조건을 만족하지 못해 빠진다.

  • NATURAL JOIN 은 동명 열인 지역까지 비교해 강민서·윤재희 2행만 남는다.
  • ON 조인은 양쪽 부서코드가 모두 남아 접두어 없는 부서코드가 모호하다는 오류가 난다.
  • CROSS JOIN 도 부서코드가 두 테이블에 있어 같은 모호성 오류가 난다.
문제 28
다음 SQL의 실행 결과에서 건수와 최저가를 순서대로 나열한 것은?

[상품]

상품코드분류가격
P1A3000
P2A5000
P3B2000
P4B4000
P5C4500
P6C1500
SELECT COUNT(*) AS 건수, MIN(가격) AS 최저가
  FROM 상품
 WHERE 가격 > ALL (SELECT 가격
                     FROM 상품
                    WHERE 분류 = 'B');
13, 4000
22, 4500
32, 2000
44, 3000
정답 및 해설

> ALL은 서브쿼리가 돌려준 모든 값보다 커야 하므로 B 분류 가격 2000·4000 중 최댓값 4000을 넘는 행만 남는다.

4000을 넘는 상품은 P2(5000)와 P5(4500) 두 행이므로 건수는 2, 최저가는 4500이다.

  • 4건·3000은 최솟값 2000만 넘으면 되는 ANY 로 읽은 결과다.
  • 3건·4000은 같은 값도 포함하는 >= ALL 로 읽은 결과다.
  • 2건·2000은 서브쿼리 값과 같은 행을 고르는 IN 의 결과다.
문제 29
각 강의에서 그 강의 평균 점수를 넘는 수강 행만 다음 [결과]처럼 조회하려 한다. ( ㉠ )에 들어갈 조건으로 옳은 것은?

[수강]

학생번호강의코드점수
S1DB80
S2DB60
S3DB70
S1OS90
S2OS50
S4OS85
S3NW62
S4NW58
SELECT A.학생번호, A.강의코드, A.점수
  FROM 수강 A
 WHERE A.점수 > (SELECT AVG(B.점수)
                   FROM 수강 B
                  WHERE ( ㉠ ))
 ORDER BY A.강의코드, A.학생번호;

[결과]

학생번호강의코드점수
S1DB80
S3NW62
S1OS90
S4OS85
1B.학생번호 = A.학생번호
2A.강의코드 IS NOT NULL
3B.강의코드 = A.강의코드
4B.점수 >= A.점수
정답 및 해설

바깥 행의 강의코드로 서브쿼리를 묶는 연관 서브쿼리 조건 B.강의코드 = A.강의코드를 써야 행마다 그 강의의 평균과 비교한다.

DB 평균 70, OS 평균 75, NW 평균 60이므로 S1(DB 80), S3(NW 62), S1(OS 90), S4(OS 85) 4행이 남고 평균과 같은 S3(DB 70)은 빠진다.

  • 학생번호 로 묶으면 학생별 평균과 비교해 S2 의 DB 60 같은 행이 섞인다.
  • 자기 점수 이상인 점수의 평균은 자기 점수 미만일 수 없어 결과가 0행이다.
  • 바깥 열의 NULL 여부만 보면 전체 평균 69.375 와 비교하게 되어 S3 의 DB 70 이 들어온다.
문제 30
서브쿼리와 뷰(View)에 대한 설명으로 적절하지 않은 것은?
1인라인 뷰는 FROM 절에 쓰는 서브쿼리다
2스칼라 서브쿼리는 값 하나만 반환해야 한다
3뷰는 조회 결과 데이터를 따로 저장한다
4뷰로 테이블 구조 변경의 영향을 줄인다
정답 및 해설

뷰는 SELECT 문 정의만 저장하는 가상 테이블이고, 조회할 때마다 기반 테이블에서 데이터를 가져오므로 결과를 따로 저장하지 않는다.

결과를 물리적으로 저장하는 것은 구체화 뷰(Materialized View) 같은 별도 객체의 특징이다.

  • 스칼라 서브쿼리는 한 행 한 열의 값 하나를 돌려주어야 한다.
  • FROM 절 서브쿼리를 인라인 뷰라 부른다.
  • 뷰는 논리적 독립성을 주어 기반 구조 변경의 영향을 줄인다.
문제 31
다음 ㉠, ㉡ SQL의 결과 행 수를 순서대로 나열한 것은?

[온라인주문]

고객번호
1
2
2
3
(null)

[매장주문]

고객번호
3
4
4
(null)
㉠ SELECT 고객번호 FROM 온라인주문
   UNION
   SELECT 고객번호 FROM 매장주문;

㉡ SELECT 고객번호 FROM 온라인주문
   UNION ALL
   SELECT 고객번호 FROM 매장주문;
15, 9
27, 9
34, 7
44, 9
정답 및 해설

UNION은 두 결과를 합친 뒤 전체 중복을 제거하므로 1, 2, 3, 4, NULL 의 5행이고, UNION ALL 은 중복을 그대로 두어 5+4=9행이다.

집합 연산의 중복 판정에서 NULL 은 서로 같은 값으로 취급되어 한 행으로 남는다.

  • 4행은 NULL 을 결과에서 빼 버린 계산이다.
  • 7행은 두 테이블에 걸친 중복만 지우고 한 테이블 안의 2·4 중복을 남긴 계산이다.
  • UNION ALL 도 NULL 행을 지우지 않으므로 7행이 될 수 없다.
문제 32
다음 SQL의 [집합 연산자] 자리에 연산자를 바꿔 넣어 실행한 결과에 대한 설명으로 옳은 것은? (MINUS 는 Oracle 의 차집합 연산자로 EXCEPT 와 같다)

[봄학기]

학번
10
20
20
30
(null)

[가을학기]

학번
20
40
(null)
SELECT 학번 FROM 봄학기
[집합 연산자]
SELECT 학번 FROM 가을학기;
1MINUS 결과는 3행이다
2INTERSECT 결과는 2행이다
3UNION 결과에 NULL 행은 없다
4UNION ALL 결과는 7행이다
정답 및 해설

INTERSECT는 양쪽에 모두 있는 값을 중복 없이 돌려주는데, 집합 연산은 NULL 을 같은 값으로 비교하므로 20과 NULL 의 2행이 된다.

MINUS 는 봄학기에만 있는 10, 30을 중복 제거해 돌려준다.

  • MINUS 결과는 20의 중복과 무관하게 10·30 의 2행이다.
  • UNION 결과에는 NULL 이 한 행 포함된다.
  • UNION ALL 은 5행과 3행을 그대로 이어 8행이다.
문제 33
다음 SQL의 결과 행 수는?

[매출]

지점분기금액
강남Q1100
강남Q2200
강남Q150
판교Q1300
성수Q280
성수Q3120
SELECT 지점, 분기, SUM(금액) AS 합계
  FROM 매출
 GROUP BY ROLLUP(지점, 분기)
 ORDER BY 지점, 분기;
19행
26행
312행
48행
정답 및 해설

ROLLUP(지점, 분기)는 (지점, 분기) 그룹, 지점별 소계, 전체 총계를 차례로 만든다.

(지점, 분기) 조합은 강남 Q1·Q2, 판교 Q1, 성수 Q2·Q3 의 5행이고 강남 Q1 두 건은 한 행으로 합쳐진다. 여기에 지점 소계 3행과 총계 1행을 더해 9행이다.

  • 8행은 마지막 총계 행을 빠뜨린 계산이다.
  • 12행은 분기별 소계까지 만드는 CUBE 의 결과다.
  • 6행은 지점 소계 없이 총계만 더한 계산이다.
문제 34
다음 SQL의 결과에서 객실유형 열이 NULL 로 표시되는 행은 모두 몇 개인가?

[예약]

지점객실유형인원
서울스탠다드2
서울디럭스3
서울스탠다드1
부산디럭스2
부산(null)4
제주스탠다드2
SELECT 지점, 객실유형, SUM(인원) AS 합계
  FROM 예약
 GROUP BY CUBE(지점, 객실유형);
14개
26개
33개
45개
정답 및 해설

CUBE는 (지점, 객실유형)·지점·객실유형·전체의 네 수준을 모두 만들며, 객실유형이 NULL 로 보이는 행은 지점 소계, 총계, 그리고 원래 NULL 값을 가진 그룹이다.

지점 소계 3행과 총계 1행에 원본 NULL 인 부산 상세 행 1행, 객실유형별 소계 중 NULL 그룹 1행이 더해져 6개다.

  • 4개는 원본 데이터의 NULL 그룹 두 행을 모두 놓친 계산이다.
  • 5개는 객실유형별 소계에도 NULL 그룹이 생기는 점을 놓친 계산이다.
  • 3개는 지점 소계만 센 계산으로 총계를 빠뜨렸다.
문제 35
다음 [결과]가 나오도록 ( ㉠ )에 들어갈 구문으로 옳은 것은?

[판매]

지점상품수량
강남커피3
강남라떼2
판교커피4
판교(null)1
성수라떼6
SELECT 지점, 상품,
       GROUPING(지점) AS G1,
       GROUPING(상품) AS G2,
       SUM(수량) AS 합계
  FROM 판매
 GROUP BY ( ㉠ )
 ORDER BY G1, 지점, 상품;

[결과]

지점상품G1G2합계
강남(null)015
성수(null)016
판교(null)015
(null)라떼108
(null)커피107
(null)(null)101
1ROLLUP (지점, 상품)
2지점, 상품
3GROUPING SETS (지점, 상품)
4CUBE (지점, 상품)
정답 및 해설

결과에는 지점별 합계와 상품별 합계만 있고 상세 행과 총계가 없으므로 GROUPING SETS (지점, 상품)이다.

상품별 집계에서 지점이 집계로 사라진 행은 G1=1 이고, 판교의 원본 NULL 상품 그룹은 GROUPING 값이 0이라 집계 NULL 과 구분된다.

  • ROLLUP 은 지점·상품 상세 행과 총계를 함께 만든다.
  • CUBE 는 상세 행, 두 소계, 총계를 모두 만든다.
  • 단순 GROUP BY 는 상세 행만 만들고 G1·G2 가 모두 0이다.
문제 36
다음 SQL의 결과로 나오는 RNK, DRNK, RN 값을 순서대로 나열한 것은?

[게시글]

글번호조회수
A190
A2120
A390
A4150
A5120
A660
SELECT RNK, DRNK, RN
  FROM (SELECT 글번호,
               RANK() OVER (ORDER BY 조회수 DESC) AS RNK,
               DENSE_RANK() OVER (ORDER BY 조회수 DESC) AS DRNK,
               ROW_NUMBER() OVER (ORDER BY 조회수 DESC, 글번호) AS RN
          FROM 게시글) T
 WHERE 글번호 = 'A3'
 ORDER BY RN;
13, 3, 5
24, 3, 4
34, 4, 5
44, 3, 5
정답 및 해설

조회수 내림차순은 150, 120, 120, 90, 90, 60 이고 A3 은 90 동점 그룹이므로 RANK는 앞선 3행을 건너뛴 4, DENSE_RANK는 세 번째 값이라 3이다.

ROW_NUMBER 는 동점을 글번호로 다시 정렬해 A1 이 4, A3 이 5를 받는다.

  • RANK 를 3으로 보는 것은 DENSE_RANK 처럼 순위를 이어 붙인 것이다.
  • DRNK 를 4로 보는 것은 DENSE_RANK 도 순위를 건너뛴다고 본 것이다.
  • RN 을 4로 보는 것은 동점 안 정렬 기준인 글번호를 무시한 것이다.
문제 37
다음 SQL의 결과에서 누적 열 값을 위에서부터 차례로 나열한 것은?

[일매출]

지점일자금액
강남2026-03-0110
강남2026-03-0220
강남2026-03-025
강남2026-03-037
판교2026-03-0130
판교2026-03-0310
SELECT 지점, 일자, 금액,
       SUM(금액) OVER (PARTITION BY 지점
                       ORDER BY 일자) AS 누적
  FROM 일매출
 ORDER BY 지점, 일자, 금액;
110, 35, 35, 42, 30, 40
210, 15, 35, 42, 30, 40
310, 35, 35, 42, 72, 82
440, 65, 65, 82, 40, 82
정답 및 해설

윈도우 절 없이 ORDER BY 만 주면 기본 프레임이 RANGE UNBOUNDED PRECEDING이라, 강남 3월 2일 두 행은 같은 일자 전체를 포함한 35를 함께 받는다.

강남은 10, 35, 35, 42 로 누적되고 PARTITION BY 지점 때문에 판교에서 다시 시작해 30, 40 이 된다.

  • 10, 15 로 이어지는 값은 행 단위 ROWS 프레임으로 계산한 것이다.
  • 40, 65 로 시작하는 값은 지점 구분 없이 일자로만 누적한 것이다.
  • 판교가 72, 82 가 되는 것은 파티션에서 누적이 초기화되는 점을 놓친 것이다.
문제 38
다음 [결과]가 나오도록 ( ㉠ )에 들어갈 함수로 옳은 것은?

[지점주문]

지점일자금액
강남2026-04-01100
강남2026-04-02300
강남2026-04-03200
판교2026-04-01500
판교2026-04-02400
SELECT 지점, 일자, 금액,
       ( ㉠ ) OVER (PARTITION BY 지점
                    ORDER BY 일자) AS 비교값
  FROM 지점주문
 ORDER BY 지점, 일자;

[결과]

지점일자금액비교값
강남2026-04-01100(null)
강남2026-04-02300100
강남2026-04-03200300
판교2026-04-01500(null)
판교2026-04-02400500
1LEAD(금액, 1, 0)
2LAG(금액)
3FIRST_VALUE(금액)
4MAX(금액)
정답 및 해설

결과의 비교값은 같은 지점에서 바로 앞 일자의 금액이고 지점별 첫 행이 NULL 이므로 LAG(금액)이다.

강남은 NULL, 100, 300, 판교는 NULL, 500 이 되어 PARTITION BY 경계에서 이전 값이 끊긴다.

  • LEAD 는 다음 행 값을 가져와 강남이 300, 200, 0 이 된다.
  • FIRST_VALUE 는 기본 프레임의 첫 행이라 강남이 모두 100 이다.
  • MAX 는 누적 최댓값이라 강남이 100, 300, 300 이 된다.
문제 39
다음 SQL의 결과로 나오는 조와 백분위 값을 순서대로 나열한 것은?

[영업실적]

사원명실적
가람95
나래88
다온81
라희74
마루67
바다60
SELECT 조, 백분위
  FROM (SELECT 사원명,
               NTILE(4) OVER (ORDER BY 실적 DESC) AS 조,
               PERCENT_RANK() OVER (ORDER BY 실적 DESC) AS 백분위
          FROM 영업실적) T
 WHERE 사원명 = '마루'
 ORDER BY 조;
14, 0.8
23, 0.8
34, 0.83
43, 0.83
정답 및 해설

6행을 NTILE(4)로 나누면 나머지 2행을 앞 그룹부터 1개씩 더 주어 2, 2, 1, 1행이 되므로 다섯 번째인 마루는 3조다.

PERCENT_RANK는 (순위-1)/(전체 행 수-1)이므로 순위 5인 마루는 4/5 = 0.8 이다.

  • 4조는 나머지 행을 뒤쪽 그룹에 몰아 1, 1, 2, 3, 4, 4 로 나눈 것이다.
  • 0.83 은 순위를 전체 행 수로 나눈 CUME_DIST 식 계산이다.
  • 4조와 0.83 은 두 계산을 모두 잘못 적용한 값이다.
문제 40
Oracle 에서 다음 SQL을 실행했을 때 결과의 상품명을 출력 순서대로 나열한 것은? (상품판매 테이블은 표의 순서대로 입력되었다)

[상품판매]

상품명판매량
노트북120
스피커180
키보드(null)
마우스300
책상90
모니터250
SELECT 상품명, 판매량
  FROM (SELECT 상품명, 판매량
          FROM 상품판매
         ORDER BY 판매량 DESC, 상품명)
 WHERE ROWNUM <= 3;
1노트북, 스피커, 키보드
2책상, 노트북, 스피커
3마우스, 모니터, 스피커
4키보드, 마우스, 모니터
정답 및 해설

인라인 뷰에서 먼저 정렬한 뒤 ROWNUM을 매기므로 정렬 순서의 앞 3행이 나오는데, Oracle 은 NULL 을 최댓값으로 취급해 DESC 정렬 맨 앞에 둔다.

그래서 판매량이 NULL 인 키보드가 첫 행이 되고 마우스(300), 모니터(250)가 뒤따른다.

  • 마우스부터 시작하는 것은 DESC 에서도 NULL 이 뒤로 간다고 본 것이다.
  • 입력 순서 앞 3건이 나오는 것은 정렬 전에 ROWNUM 을 매기는 경우다.
  • 책상부터 시작하는 것은 오름차순 정렬로 잘못 읽은 것이다.
문제 41
SQL Server 에서 실행할 때 오류가 발생하는 SQL은? (상품 테이블에 상품명, 판매량 열이 있다)
1SELECT TOP(50) PERCENT 상품명 FROM 상품
2SELECT 상품명 FROM 상품 ORDER BY 1 OFFSET 2 ROWS
3SELECT TOP(2) 상품명 FROM 상품 ORDER BY 판매량 DESC
4SELECT TOP(3) WITH TIES 상품명, 판매량 FROM 상품
정답 및 해설

WITH TIES는 마지막 순위와 같은 값을 가진 행을 함께 돌려주는 옵션이라 동점 기준이 되는 ORDER BY 절이 반드시 있어야 하며, 없으면 오류가 난다.

TOP 만 단독으로 쓰거나 PERCENT 를 붙인 경우는 ORDER BY 없이도 실행되며 다만 어떤 행이 나올지 보장되지 않는다.

  • TOP(2)와 ORDER BY 를 함께 쓴 상위 2건 조회는 정상이다.
  • TOP(50) PERCENT 는 전체의 절반 행을 돌려주는 정상 구문이다.
  • ORDER BY 뒤 OFFSET 만 쓴 구문은 앞 2행을 건너뛰는 정상 구문이다.
문제 42
Oracle 에서 다음 SQL을 실행했을 때 결과의 이름을 단계 순서대로 나열한 것은?

[직원]

사번이름상사사번
1한서진(null)
2오지훈1
3정다인1
4배수아2
5노태윤4
6문가은4
7유하람3
SELECT LEVEL AS 단계, 이름
  FROM 직원
 START WITH 사번 = 4
CONNECT BY PRIOR 상사사번 = 사번
 ORDER BY 단계;
1배수아, 노태윤, 문가은
2배수아, 오지훈
3배수아, 오지훈, 한서진
4한서진, 오지훈, 배수아
정답 및 해설

PRIOR 상사사번 = 사번은 이전 행의 상사사번을 사번으로 갖는 행, 곧 상사 쪽으로 올라가는 역방향 전개다.

시작 행 배수아가 LEVEL 1이고 그 상사 오지훈이 2, 루트 한서진이 3이 되며, 루트의 상사사번이 NULL 이라 전개가 끝난다.

  • 부하 노태윤·문가은으로 내려가는 것은 PRIOR 사번 = 상사사번 인 순방향이다.
  • 한서진을 1단계로 보는 것은 LEVEL 이 시작 행에서 1부터 매겨지는 점을 놓친 것이다.
  • 루트도 연결 조건을 만족해 포함되므로 오지훈에서 끝나지 않는다.
문제 43
Oracle 에서 다음 SQL을 실행한 결과에 대한 설명으로 옳은 것은?

[카테고리]

코드이름상위코드
C1가전(null)
C2컴퓨터C1
C3노트북C2
C4주방C1
C5도서(null)
SELECT 이름,
       CONNECT_BY_ROOT 이름 AS 루트,
       CONNECT_BY_ISLEAF AS 리프,
       SYS_CONNECT_BY_PATH(이름, '/') AS 경로
  FROM 카테고리
 START WITH 상위코드 IS NULL
CONNECT BY PRIOR 코드 = 상위코드;
1도서 행의 경로 값은 /도서 이다
2노트북 행의 루트 값은 컴퓨터이다
3주방 행의 리프 값은 0이다
4컴퓨터 행의 리프 값은 1이다
정답 및 해설

SYS_CONNECT_BY_PATH는 루트부터 현재 행까지 값을 구분자로 이어 붙이되 맨 앞에도 구분자를 두므로, 단독 루트인 도서 행의 경로는 /도서 이다.

CONNECT_BY_ROOT는 그 행이 속한 트리의 루트 값을, CONNECT_BY_ISLEAF 는 자식이 없으면 1, 있으면 0을 돌려준다.

  • 노트북의 루트는 시작 행인 가전이며 컴퓨터는 바로 위 상위일 뿐이다.
  • 주방은 하위 행이 없는 말단이라 리프 값이 1이다.
  • 컴퓨터는 하위에 노트북이 있어 리프 값이 0이다.
문제 44
Oracle 에서 [예약] 테이블에 다음 SQL 을 실행한 결과로 옳은 것은?

[예약]

예약번호객실요일인원
1A토2
2A일3
3A토1
4B토4
5C금2
6C금3
7D일2
SELECT *
  FROM (SELECT 객실, 요일, 인원 FROM 예약)
 PIVOT (SUM(인원)
        FOR 요일 IN ('토' AS 토, '일' AS 일))
 ORDER BY 객실;
1
객실토일
A33
B4(null)
D(null)2
2
객실토일
A33
B40
C00
D02
3
객실토일금
A33(null)
B4(null)(null)
C(null)(null)5
D(null)2(null)
4
객실토일
A33
B4(null)
C(null)(null)
D(null)2
정답 및 해설

PIVOT은 IN 목록에 적은 '토'·'일'만 열로 만들고, 인라인 뷰에 남은 객실로 묶으므로 객실 A·B·C·D 네 행이 나온다.

객실 C 는 금요일 예약뿐이라 두 피벗 열이 모두 NULL 인 행으로 남고, 값이 없는 칸은 SUM 대상이 없어 0 이 아닌 NULL 로 표시된다.

  • 객실 C 가 빠진 표는 IN 목록 밖 값만 가진 그룹이 사라진다고 본 것이다.
  • 빈 칸을 0 으로 채운 표는 집계 대상이 없는 SUM 이 0 을 돌려준다고 본 것이다.
  • 금 열이 생긴 표는 IN 목록에 없는 값도 열로 펼쳐진다고 본 것이다.
문제 45
Oracle 에서 다음 SQL을 실행했을 때 결과에 포함되는 아이디는? (대소문자 구분은 기본 설정을 따른다)

[회원]

아이디가입일
kim012026-01-05
lee72026-01-09
park1232026-02-11
Choi222026-02-20
han_092026-03-02
yoon992026-03-15
jo12x2026-03-28
SELECT 아이디
  FROM 회원
 WHERE REGEXP_LIKE(아이디, '^[a-z]+[0-9]{2}$')
 ORDER BY 아이디;
1han_09
2park123
3yoon99
4Choi22
정답 및 해설

패턴은 처음부터 소문자 1개 이상, 이어서 숫자 정확히 2개로 끝나야 하므로 yoon99 가 일치하고 결과는 kim01, yoon99 두 행이다.

REGEXP_LIKE 는 기본 설정에서 대소문자를 구분하며 ^ 와 $ 가 문자열 전체를 감싸 중간 일치를 허용하지 않는다.

  • park123 은 숫자가 3개라 $ 앞의 {2} 를 만족하지 못한다.
  • Choi22 는 첫 글자 C 가 대문자라 [a-z] 에 맞지 않는다.
  • han_09 는 밑줄이 문자 클래스에 없어 일치하지 않는다.
문제 46
다음 UPDATE 문을 실행했을 때 수정되는 행의 수는?

[재고]

상품코드수량
A5
B20
C(null)
D15
E30
UPDATE 재고
   SET 수량 = 수량 + 10
 WHERE 수량 < 20;
11건
23건
32건
44건
정답 및 해설

UPDATE 는 WHERE 조건이 참인 행만 바꾸며, 수량이 NULL 인 C 는 비교 결과가 UNKNOWN이라 대상에서 빠진다.

조건을 만족하는 행은 A(5)와 D(15)뿐이므로 2건이 수정되고, 20인 B 는 미만 조건의 경계라 제외된다.

  • 3건은 NULL 인 C 까지 조건을 만족한다고 본 계산이다.
  • 4건은 경계값 20과 NULL 을 모두 포함한 계산이다.
  • 1건은 A 만 조건에 맞는다고 본 계산으로 D 를 놓쳤다.
문제 47
빈 예약 테이블에 대해 Oracle 에서 다음 문장을 차례로 실행했다. 마지막 SELECT 결과로 나오는 예약번호는?
INSERT INTO 예약 VALUES (10, '하윤');
SAVEPOINT SP1;
INSERT INTO 예약 VALUES (20, '시우');
SAVEPOINT SP2;
DELETE FROM 예약 WHERE 예약번호 = 10;
ROLLBACK TO SAVEPOINT SP1;
INSERT INTO 예약 VALUES (30, '지아');
COMMIT;

SELECT 예약번호 FROM 예약 ORDER BY 예약번호;
110, 20, 30
230
310, 30
420, 30
정답 및 해설

ROLLBACK TO SAVEPOINT SP1은 SP1 이후의 작업만 취소하므로 20 입력과 10 삭제가 모두 되돌려지고, SP1 이전의 10 입력은 남는다.

이어서 30을 입력하고 COMMIT으로 확정하므로 10과 30이 남는다.

  • 10, 20, 30이 남는 것은 SP2 까지만 되돌려 20 입력이 살아 있다고 본 결과다.
  • 30만 남는 것은 20 입력은 취소되고 10 삭제는 그대로라고 본 것이다.
  • 20과 30이 남는 것은 롤백이 10 삭제를 되돌리지 않는다고 본 것이다.
문제 48
다음 테이블을 만든 뒤 ㉠~㉣을 각각 실행할 때 제약조건 위반으로 실패하는 것은?
CREATE TABLE 회원 (
  회원번호 INT PRIMARY KEY,
  이메일   VARCHAR(50) UNIQUE,
  이름     VARCHAR(20) NOT NULL,
  나이     INT CHECK (나이 >= 14)
);
INSERT INTO 회원 VALUES (1, 'a@mail.com', '서윤', 20);

㉠ INSERT INTO 회원 VALUES (2, NULL, '도하', 30);
㉡ INSERT INTO 회원 VALUES (3, 'b@mail.com', '이안', 14);
㉢ INSERT INTO 회원 VALUES (4, 'c@mail.com', NULL, 25);
㉣ INSERT INTO 회원 VALUES (5, 'd@mail.com', '나린', NULL);
1㉠
2㉢
3㉡
4㉣
정답 및 해설

이름 열에 NOT NULL 제약이 있으므로 이름에 NULL 을 넣는 ㉢은 실패한다.

UNIQUE 열에는 NULL 을 넣을 수 있고, CHECK 조건은 결과가 거짓일 때만 거부하므로 NULL 처럼 판단할 수 없는 값은 통과한다.

  • ㉠은 이메일이 NULL 이지만 UNIQUE 는 NULL 입력을 막지 않는다.
  • ㉡은 나이 14가 이상 조건의 경계값이라 CHECK 를 만족한다.
  • ㉣은 나이가 NULL 이라 CHECK 결과가 UNKNOWN 으로 통과된다.
문제 49
Oracle 에서 상품 테이블(상품명, 단가, 비고 열 보유)에 실행할 때 문법 오류가 발생하는 것은?
1ALTER TABLE 상품 DROP COLUMN 비고
2ALTER TABLE 상품 ADD (원산지 VARCHAR2(20))
3ALTER TABLE 상품 MODIFY (상품명 VARCHAR2(100))
4ALTER TABLE 상품 RENAME 단가 TO 판매가
정답 및 해설

Oracle 에서 열 이름을 바꾸려면 ALTER TABLE 상품 RENAME COLUMN 단가 TO 판매가처럼 RENAME COLUMN 키워드가 있어야 하므로 COLUMN 을 빠뜨린 구문은 오류다.

테이블 이름 변경은 RENAME 옛이름 TO 새이름 또는 ALTER TABLE … RENAME TO 로 쓴다.

  • ADD 는 괄호 안에 새 열 정의를 적어 열을 추가하는 정상 구문이다.
  • MODIFY 는 기존 열의 길이·타입을 바꾸는 Oracle 정상 구문이다.
  • DROP COLUMN 은 지정한 열을 삭제하는 정상 구문이다.
문제 50
Oracle 에서 다음 문장을 차례로 실행한 뒤의 상태로 옳은 것은?
-- 관리자
GRANT SELECT ON 주문 TO U1 WITH GRANT OPTION;
-- U1
GRANT SELECT ON 주문 TO U2;
-- 관리자
REVOKE SELECT ON 주문 FROM U1;
1U1, U2 모두 권한을 잃는다
2어느 쪽 권한도 회수되지 않는다
3U2 때문에 REVOKE 가 실패한다
4U1 만 권한을 잃는다
정답 및 해설

WITH GRANT OPTION으로 받은 객체 권한을 회수하면 그 사용자가 다른 사용자에게 넘겨준 권한까지 연쇄적으로 회수되므로 U1 과 U2 모두 SELECT 권한을 잃는다.

연쇄 회수가 일어나지 않는 것은 시스템 권한을 WITH ADMIN OPTION 으로 넘긴 경우다.

  • U1 만 잃는 것은 WITH ADMIN OPTION 의 동작과 혼동한 것이다.
  • 재부여한 권한이 있어도 REVOKE 는 실패하지 않는다.
  • REVOKE 를 실행했으므로 U1 의 권한은 확실히 회수된다.