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

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

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

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

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

총 50문항 · 객관식 · 정답·해설 포함
문제 1
학원 관리 DB에서 수강생 테이블에 인덱스를 추가하고 저장 파일 구조를 바꾸었는데도 개념 스키마와 응용 프로그램은 고칠 필요가 없었다. 이 성질을 무엇이라 하는가?
1물리적 데이터 독립성
2논리적 독립성
3데이터 중복의 최소화
4참조 무결성 보장
정답 및 해설

내부 스키마(저장 구조·인덱스)가 바뀌어도 개념 스키마와 응용 프로그램이 영향을 받지 않는 성질을 물리적 데이터 독립성이라 한다.

개념 스키마가 바뀌어도 외부 스키마와 응용 프로그램이 유지되는 성질은 논리적 데이터 독립성으로 구분한다.

  • 논리적 독립성은 개념 스키마 변경에 대한 성질이라 이 상황과 다르다.
  • 데이터 중복 최소화는 독립성이 아니라 통합 저장의 목적이다.
  • 참조 무결성은 FK 값이 부모 PK 에 존재해야 한다는 제약이다.
문제 2
다음은 학원 업무의 ERD이다. 각 엔터티를 유형·무형과 발생 시점에 따라 분류한 것으로 옳지 않은 것은?

그림

1강사 — 유형·기본 엔터티
2출석 — 사건·중심 엔터티
3과목 — 개념·기본 엔터티
4수강생 — 유형이자 키(기본) 엔터티
정답 및 해설

출석은 수강신청에서 다시 파생되어 매일 쌓이는 데이터이므로 행위 엔터티이며 중심 엔터티가 아니다.

중심 엔터티는 기본 엔터티로부터 생겨 업무의 중심이 되는 엔터티이고, 행위 엔터티는 그 아래에서 다시 파생되어 자주 발생·변경된다.

  • 강사는 물리적 형태가 있고 독립적으로 생성되는 유형·기본 엔터티다.
  • 과목은 형태가 없는 개념이며 다른 엔터티 없이 생기는 기본 엔터티다.
  • 수강생은 실체가 있는 사람이고 다른 엔터티 없이 먼저 존재하는 키(기본) 엔터티다.
문제 3
수강생 한 명이 휴대전화·자택 전화·보호자 전화 등 연락처를 여러 개 가질 수 있다. '연락처' 속성의 설계로 가장 적절한 것은?
1파생 속성이라 계산해서 채워 넣는다
2설계 속성이라 임의 순번을 붙여 관리한다
3다중값 속성이라 별도 엔터티로 나눈다
4복합 속성이라 하위 속성으로 쪼갠다
정답 및 해설

한 인스턴스가 같은 속성에 값을 여러 개 갖는 연락처는 다중값 속성이므로 수강생연락처 같은 별도 엔터티로 분리해 1:N 관계로 연결한다.

속성은 인스턴스마다 하나의 값만 가져야 하며, 한 칸에 여러 번호를 넣으면 제1정규형을 위반한다.

  • 복합 속성은 주소처럼 한 값을 의미 단위로 나누는 경우라 값이 여러 개인 것과 다르다.
  • 파생 속성은 다른 속성에서 계산되는 값이라 연락처와 무관하다.
  • 설계 속성은 업무에 없던 코드·순번을 설계상 새로 만든 속성이다.
문제 4
학원 업무에서 관계를 존재 관계와 행위 관계로 나눌 때, 행위 관계에 해당하는 것은?
1수강생이 강좌를 신청한다
2과목이 한 계열에 속한다
3강사가 한 지점에 소속된다
4강의실이 한 층에 배치된다
정답 및 해설

수강생이 강좌를 신청하는 것처럼 어떤 행위가 일어나야 맺어지는 관계를 행위 관계라 하며, 그 결과가 수강신청 같은 행위 엔터티로 남는다.

소속·배치·포함처럼 한 엔터티의 존재 자체로 다른 엔터티와 연결되는 관계는 존재 관계로 분류한다.

  • 강사의 지점 소속은 행위 없이 존재로 맺어지는 존재 관계다.
  • 강의실의 층 배치는 위치상 포함되는 존재 관계다.
  • 과목의 계열 소속도 분류상 포함되는 존재 관계다.
문제 5
강좌 → 강좌회차 → 회차출석처럼 식별자 관계(실선)만으로 하위 엔터티를 계속 연결할 때 나타나는 현상으로 옳은 것은?
1자식 인스턴스를 부모 없이 먼저 만들 수 있다
2하위로 갈수록 주식별자 속성이 늘어난다
3관계선이 모두 점선으로 그려진다
4부모 식별자가 일반 속성으로 내려간다
정답 및 해설

식별자 관계는 부모 주식별자를 자식 주식별자에 포함하므로 단계가 깊어질수록 상속된 PK 속성이 누적되어 복합키가 커진다.

그 결과 하위 테이블의 조인 조건이 길어지므로 독립 생명주기를 갖는 자식은 비식별자 관계(점선)로 끊는 것을 검토한다.

  • 부모 없이 자식을 먼저 만들 수 있는 것은 비식별자 관계의 특징이다.
  • 부모 식별자가 일반 속성(FK)으로만 내려가는 것은 비식별자 관계다.
  • 점선은 비식별자 관계 표기이며 식별자 관계는 실선이다.
문제 6
[수강내역(수강생번호, 수강생명, 강좌코드, 강좌명, 강사명, 신청일)] 하나로 관리하던 데이터를 다음 ERD처럼 정규화하였다. 이에 대한 설명으로 옳지 않은 것은?

그림

1신청 전에도 강좌를 미리 등록할 수 있다
2모든 조회 질의의 조인 횟수가 줄어든다
3강좌명이 바뀌면 강좌 한 행만 고친다
4수강생별 강좌명 조회에 조인이 필요하다
정답 및 해설

정규화는 중복을 없애 갱신·삽입 이상을 제거하지만 테이블이 나뉘므로 여러 엔터티 정보를 함께 보는 조회에서는 오히려 조인이 늘어난다.

그래서 조회 위주 업무에서는 성능을 위해 반정규화를 검토하기도 한다.

  • 강좌명은 강좌 테이블에만 있으므로 한 행만 수정하면 된다.
  • 강좌를 독립 테이블로 두어 신청 없이도 입력할 수 있다.
  • 수강생별 강좌명은 수강신청과 강좌를 조인해야 얻는다.
문제 7
다음 ERD를 그대로 테이블로 구현하였다. '강좌가 개설된 지점'의 지점명별 수강신청 건수를 구하는 방법으로 옳은 것은?

그림

1수강생의 지점코드를 거쳐 지점과 조인한다
2강좌와 지점만 조인해 건수를 센다
3수강신청과 지점을 지점코드로 바로 조인한다
4수강신청·강좌·지점을 두 조건으로 조인한다
정답 및 해설

비식별자 관계라 수강신청에는 지점코드가 없고 강좌번호만 FK 로 있으므로 수강신청.강좌번호=강좌.강좌번호와 강좌.지점코드=지점.지점코드 두 조건으로 세 테이블을 조인해야 한다.

관계(PK-FK)를 따라 조인하는 것이 원칙이며, 이름이 같은 지점코드라도 어느 관계에서 온 FK 인지 구분해야 한다.

  • 수강신청에는 지점코드 열이 없어 지점과 바로 조인할 수 없다.
  • 수강생의 지점코드는 등록 지점이라 강좌 개설 지점과 다를 수 있다.
  • 강좌와 지점만으로는 강좌 수만 알 뿐 신청 건수를 셀 수 없다.
문제 8
업무 규칙상 수강신청 1건은 1회차 납부 1건과 반드시 함께 등록되어야 한다. 다음 데이터와 작업 기록에 대한 설명으로 옳은 것은?

[수강신청]

신청번호수강생번호신청일
R1S12026-03-02
R2S22026-03-02
R3S12026-03-04

[납부]

신청번호회차금액
R11150000
R21120000
R31150000
R32150000

[작업 기록]

INSERT INTO 수강신청 VALUES ('R4', 'S3', DATE '2026-03-05');
COMMIT;
INSERT INTO 납부 VALUES ('R4', 1, 180000);  -- 제약 위반 오류
ROLLBACK;
1R3은 납부가 두 건이라 규칙을 어겼다
2R4는 신청만 남아 규칙을 어긴 상태다
3두 INSERT 는 따로 커밋해야 한다
4ROLLBACK 으로 R4 신청도 취소된다
정답 및 해설

R4 신청은 이미 COMMIT 으로 확정된 뒤 납부 입력이 실패했으므로 ROLLBACK 을 해도 신청만 남아 함께 등록 규칙을 어긴 상태가 된다.

두 INSERT 를 하나의 트랜잭션으로 묶고 모두 성공한 뒤 한 번만 커밋해야 원자성이 지켜진다.

  • ROLLBACK 은 마지막 COMMIT 이후 작업만 되돌리므로 R4 신청은 남는다.
  • 1회차 납부가 있으면 되므로 납부가 두 건인 R3 은 규칙에 맞다.
  • 따로 커밋하면 한쪽만 저장되는 상태가 생겨 오히려 위험하다.
문제 9
수강생 테이블의 '보호자연락처' 열에 NULL 이 들어 있을 때, NULL 에 대한 설명으로 옳은 것은?
1값이 없거나 미정인 상태를 뜻한다
2COUNT(열)은 NULL 행도 센다
3NULL+숫자는 그 숫자 값이 된다
4NULL 끼리 = 비교하면 참이다
정답 및 해설

NULL 은 0 이나 공백이 아니라 값이 없거나 아직 알 수 없는 상태를 나타내는 표시다.

그래서 NULL 과의 비교는 UNKNOWN, 산술 연산 결과는 NULL 이 되고 집계 함수는 NULL 행을 빼고 계산한다.

  • NULL = NULL 도 UNKNOWN 이므로 참이 아니며 IS NULL 로 판별한다.
  • NULL 이 포함된 산술 연산의 결과는 NULL 이다.
  • COUNT(열)은 NULL 인 행을 세지 않고 COUNT(*)만 모든 행을 센다.
문제 10
수강신청 엔터티의 본질식별자가 (수강생번호+강좌번호+신청일자)이고, 그 아래에 출석·납부·평가 엔터티가 식별자 관계로 연결된다. 인조식별자 '신청번호'를 주식별자로 두는 이유로 가장 적절한 것은?
1하위 엔터티로 상속될 식별자가 단순해진다
2본질식별자의 유니크 제약이 불필요하다
3수강생의 중복 신청을 자동으로 막는다
4식별자만 보고도 업무 의미를 알 수 있다
정답 및 해설

본질식별자가 세 속성의 복합키이면 하위 엔터티마다 모두 상속되어 PK 와 조인 조건이 길어지므로 단일 인조식별자로 바꾸면 상속 식별자가 단순해진다.

대신 인조식별자는 업무 중복을 막지 못하므로 본질식별자 조합에 별도 유니크 제약을 두어야 한다.

  • 순번만으로는 같은 신청의 중복 입력을 막을 수 없다.
  • 업무 의미가 드러나는 쪽은 본질식별자이고 인조식별자는 의미가 없다.
  • 중복 방지를 위해 본질식별자 조합에 유니크 제약이 오히려 필요하다.
문제 11
다음 중 SQL 문의 종류가 나머지 셋과 다른 것은?
1TRUNCATE
2ROLLBACK
3COMMIT
4SAVEPOINT
정답 및 해설

TRUNCATE 는 테이블 구조는 남기고 데이터를 모두 지우는 DDL 로 분류되며 나머지 셋은 트랜잭션을 제어하는 TCL 이다.

TCL 은 COMMIT·ROLLBACK·SAVEPOINT 처럼 DML 작업의 확정과 취소 단위를 다루는 명령이다.

  • COMMIT 은 트랜잭션의 변경을 확정하는 TCL 이다.
  • SAVEPOINT 는 부분 롤백 지점을 지정하는 TCL 이다.
  • ROLLBACK 은 커밋 전 변경을 취소하는 TCL 이다.
문제 12
다음 [강좌] 테이블에 대해 SQL을 실행한 결과로 옳은 것은?

[강좌]

강좌번호과목레벨수강료
1영어A100
2영어A100
3영어B100
4수학A120
5수학A150
6수학A120
SELECT DISTINCT 과목 || 레벨 AS 반,
       수강료 + 20 * 2 AS 금액
  FROM 강좌
 ORDER BY 반, 금액;
1
반금액
수학A160
영어A140
영어B140
2
반금액
수학A280
수학A340
영어A240
영어B240
3
반금액
수학A160
수학A190
영어A140
영어B140
4
반금액
수학A160
수학A160
수학A190
영어A140
영어A140
영어B140
정답 및 해설

곱셈이 덧셈보다 먼저라 금액은 수강료+40이고, DISTINCT 는 SELECT 목록 전체(반, 금액) 조합이 같은 행만 하나로 합친다.

영어A·140 두 행과 수학A·160 두 행이 각각 하나로 줄어 4행이 남고, 금액이 다른 수학A 160·190 은 서로 다른 행이라 모두 남는다.

  • (수강료+20)*2 로 계산하면 금액이 240·280 처럼 커져 우선순위를 어긴다.
  • DISTINCT 를 빼먹으면 중복 행이 그대로 남아 6행이 된다.
  • DISTINCT 가 첫 열에만 적용된다고 보면 수학A 가 한 행으로 줄어든다.
문제 13
다음 SQL에 대한 설명으로 옳은 것은? (개강일은 [강좌] 테이블의 열이다)
SELECT 강사번호, COUNT(*) AS 강좌수
  FROM 강좌
 GROUP BY 강사번호
 ORDER BY 개강일;
1SELECT 목록에 있는 열로만 정렬된다
2강사별 개강일 순으로 정렬되어 나온다
3그룹화 뒤라 개강일로는 정렬할 수 없다
4정렬이 WHERE 보다 먼저 실행된다
정답 및 해설

논리적 실행 순서가 FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY 이므로 그룹화 뒤의 ORDER BY 에서는 그룹 기준 열과 집계 결과만 쓸 수 있어 개강일 정렬은 오류가 난다.

그룹을 만들지 않은 일반 SELECT 라면 SELECT 목록에 없는 열로도 정렬할 수 있다.

  • GROUP BY 가 없을 때는 SELECT 목록 밖의 열로도 정렬된다.
  • 강사별로 개강일이 여러 개라 한 값으로 정렬할 수 없어 오류다.
  • ORDER BY 는 가장 마지막에 실행되며 WHERE 가 먼저다.
문제 14
다음 [강좌] 테이블에 대해 SQL을 실행한 결과로 옳은 것은? (Oracle 기준)

[강좌]

강좌명개강일종강일
회화A2026-01-152026-02-14
문법B2026-02-022026-03-01
작문C2026-03-102026-04-09
독해D2026-04-012026-04-30
SELECT 강좌명,
       종강일 - 개강일 AS 기간,
       TO_CHAR(LAST_DAY(개강일), 'DD') AS 말일
  FROM 강좌
 WHERE 개강일 >= TO_DATE('2026-02-01', 'YYYY-MM-DD')
 ORDER BY 개강일;
1
강좌명기간말일
문법B2828
작문C3131
독해D3030
2
강좌명기간말일
문법B2728
작문C3031
독해D2930
3
강좌명기간말일
회화A3031
문법B2728
작문C3031
독해D2930
4
강좌명기간말일
문법B2731
작문C3030
독해D2930
정답 및 해설

Oracle 에서 날짜−날짜는 두 날짜 사이의 일수(끝−시작)이고 LAST_DAY 는 그 달의 마지막 날을 돌려주며, WHERE 조건으로 2026-02-01 이후 개강한 세 강좌만 남는다.

문법B 는 2월 2일부터 3월 1일까지라 27, 2월 말일은 28 이고 작문C 는 30·31, 독해D 는 29·30 이 된다.

  • 시작일을 포함해 하루를 더하면 28·31·30 이 되지만 단순 차가 결과다.
  • 회화A 는 1월 15일 개강이라 WHERE 조건에서 빠진다.
  • LAST_DAY 는 종강일이 아니라 개강일 기준이라 문법B 의 말일은 28 이다.
문제 15
다음 SQL의 실행 결과로 옳은 것은?

[성적]

수강생명점수
가온95
나래70
다솜(null)
라희69
마루88
SELECT 수강생명,
       CASE WHEN 점수 >= 70 THEN 'B'
            WHEN 점수 >= 90 THEN 'A'
            WHEN 점수 < 70  THEN 'C'
       END AS 등급
  FROM 성적
 ORDER BY 수강생명;
1
수강생명등급
가온B
나래B
다솜C
라희C
마루B
2
수강생명등급
가온B
나래B
다솜(null)
라희C
마루B
3
수강생명등급
가온A
나래B
다솜(null)
라희C
마루B
4
수강생명등급
가온B
나래C
다솜(null)
라희C
마루B
정답 및 해설

검색형 CASE 는 WHEN 을 위에서부터 평가해 처음 참이 된 THEN 값만 돌려주므로 95점인 가온도 첫 조건(70 이상)에 걸려 B 가 된다.

점수가 NULL 인 다솜은 모든 비교가 UNKNOWN 이고 ELSE 가 없어 NULL 이며, 69점인 라희만 C 를 받는다.

  • 뒤의 90 이상 조건은 앞 조건에 먼저 걸려 한 번도 쓰이지 않는다.
  • NULL 은 70 미만 비교에서도 참이 아니라 C 가 되지 않는다.
  • 70점은 70 이상 조건을 만족하므로 나래는 B 를 받는다.
문제 16
다음 [강좌] 테이블에서 하이픈(-) 뒤의 번호만 꺼내 원하는 결과를 얻으려 한다. ( ㉠ )에 들어갈 식으로 옳은 것은? (Oracle 기준)

[강좌]

강좌코드강좌명
EN-101영어회화
MATH-202수학심화
SCI-35과학탐구
KR-7국어독해
SELECT 강좌코드,
       ( ㉠ ) AS 번호
  FROM 강좌
 ORDER BY 강좌코드;

[원하는 결과]

강좌코드번호
EN-101101
KR-77
MATH-202202
SCI-3535
1SUBSTR(강좌코드, INSTR(강좌코드, '-') + 1)
2REPLACE(강좌코드, '-', '')
3RTRIM(강좌코드, '0123456789')
4SUBSTR(강좌코드, -3)
정답 및 해설

INSTR 로 하이픈 위치를 찾고 그다음 칸부터 SUBSTR 로 끝까지 자르면 앞 글자 수와 번호 자릿수가 달라도 101·7·202·35 를 정확히 얻는다.

SUBSTR 의 길이 인수를 생략하면 시작 위치부터 문자열 끝까지 반환한다.

  • 뒤에서 3자를 자르면 SCI-35 는 -35, KR-7 은 R-7 이 된다.
  • REPLACE 는 하이픈만 지워 EN101 처럼 앞 글자가 남는다.
  • RTRIM 은 오른쪽 숫자를 지워 EN- 같은 앞부분만 남긴다.
문제 17
다음 SQL을 실행했을 때 결과 행의 수는?

[강좌]

강좌번호과목레벨수강료
1수학A90
2수학B120
3영어A80
4영어B130
5국어C100
6과학B90
7영어C150
SELECT 강좌번호, 과목
  FROM 강좌
 WHERE NOT 과목 = '수학' AND 수강료 >= 100 OR 레벨 = 'A'
 ORDER BY 강좌번호;
13
26
34
45
정답 및 해설

우선순위가 NOT > AND > OR 이므로 조건은 ((NOT 과목='수학') AND 수강료>=100) OR 레벨='A' 로 묶여 강좌 4·5·7 과 레벨 A 인 1·3 이 남아 5행이다.

NOT 은 바로 뒤 비교식 하나에만 적용되고, 수학 강좌라도 레벨이 A 면 OR 오른쪽 조건으로 통과한다.

  • NOT 을 뒤 조건 전체에 씌우면 4·5·6·7 의 4행이 된다.
  • OR 을 먼저 묶으면 수학 강좌 1 이 빠져 3·4·5·7 의 4행이 된다.
  • 레벨 A 조건까지 NOT 과 AND 로 묶였다고 보면 4·5·7 의 3행으로 줄어든다.
문제 18
[강좌] 테이블에서 WHERE 강좌명 LIKE '_어%' 조건을 만족하는 강좌명은?
1어휘특강
2중국어
3고급 영어
4영어회화
정답 및 해설

LIKE 에서 _ 는 정확히 한 글자, % 는 0개 이상의 글자를 뜻하므로 '_어%' 는 두 번째 글자가 '어'인 문자열이다.

영어회화는 첫 글자 '영' 뒤에 '어'가 오고 나머지 글자는 % 가 받아 조건을 만족한다.

  • 어휘특강은 '어'가 첫 글자라 앞의 _ 한 글자를 채우지 못한다.
  • 중국어는 두 번째 글자가 '국'이라 맞지 않는다.
  • 고급 영어는 두 번째 글자가 '급'이라 맞지 않는다.
문제 19
다음 SQL의 실행 결과로 옳은 것은?

[강좌]

강좌번호강사번호수강료
1T1120
2T180
3T1100
4T2150
5T290
6T3110
7T3130
8T3(null)
SELECT 강사번호, COUNT(*) AS 강좌수, SUM(수강료) AS 합계
  FROM 강좌
 WHERE 수강료 >= 100
 GROUP BY 강사번호
HAVING COUNT(*) >= 2
 ORDER BY 강사번호;
1
강사번호강좌수합계
T12220
T21150
T32240
2
강사번호강좌수합계
T13300
T22240
T33240
3
강사번호강좌수합계
T12220
T33240
4
강사번호강좌수합계
T12220
T32240
정답 및 해설

WHERE 가 그룹화 전에 수강료 100 이상 행만 남기므로 T1 은 120·100, T2 는 150, T3 는 110·130 만 집계되고(NULL 은 비교가 UNKNOWN 이라 제외) 이어서 HAVING 이 2건 이상인 그룹만 남긴다.

그래서 1건뿐인 T2 가 빠지고 T1(2건, 220)과 T3(2건, 240) 두 행이 나온다.

  • HAVING 을 무시하면 1건인 T2 까지 결과에 남는다.
  • 수강료가 NULL 인 행은 WHERE 에서 이미 빠져 T3 의 건수는 3 이 아니다.
  • WHERE 를 무시하고 전체 행을 세면 건수와 합계가 모두 커진다.
문제 20
다음 SQL을 실행했을 때 결과 행의 수는?

[수강생]

번호지점나이
1강남17
2강남25
3강남(null)
4분당19
5분당19
6분당(null)
7(null)30
8(null)15
SELECT CASE WHEN 나이 < 20 THEN '청소년' ELSE '성인' END AS 구분,
       지점, COUNT(*) AS 인원
  FROM 수강생
 GROUP BY CASE WHEN 나이 < 20 THEN '청소년' ELSE '성인' END, 지점
 ORDER BY 1, 2;
17
24
36
45
정답 및 해설

나이가 NULL 이면 '나이 < 20' 이 UNKNOWN 이라 ELSE 로 가서 성인이 되고, 지점이 NULL 인 행도 GROUP BY 에서 하나의 그룹을 이룬다.

강남·분당·지점 NULL 이 각각 청소년과 성인 두 그룹씩으로 묶여 6행이며, 분당의 19세 두 명은 한 그룹으로 합쳐진다.

  • 지점이 NULL 인 행을 버리면 강남·분당 네 그룹만 남아 4행이 된다.
  • 나이 NULL 행이 빠진다고 보면 분당 성인 그룹이 사라져 5행이 된다.
  • 나이 NULL 을 별도 구분으로 보면 강남·분당에 그룹이 생겨 7행으로 센다.
문제 21
다음 [강좌] 테이블 전체를 대상으로 SELECT 절에 넣어 실행했을 때 결과가 나머지 셋과 다른 것은?

[강좌]

강좌번호수강료
1100
2200
3(null)
4300
1SUM(수강료) / COUNT(수강료)
2MAX(수강료) - MIN(수강료)
3AVG(COALESCE(수강료, 0))
4AVG(수강료)
정답 및 해설

AVG·SUM·COUNT(열)은 NULL 행을 제외하고 계산하므로 AVG(수강료)는 600/3=200 이지만, COALESCE 로 NULL 을 0 으로 바꾸면 4행 모두 평균에 들어가 600/4=150 이 된다.

집계 전에 NULL 을 다른 값으로 바꾸면 분모가 달라진다는 점이 핵심이다.

  • AVG(수강료)는 NULL 을 빼고 세 값을 평균해 200 이다.
  • SUM 600 을 COUNT(수강료) 3 으로 나누어 200 이다.
  • MAX·MIN 도 NULL 을 빼고 300 과 100 으로 계산해 차가 200 이다.
문제 22
다음 SQL의 실행 결과로 옳은 것은?

[수강생]

번호이름레벨점수
1하늘중급80
2보람고급70
3구름초급95
4별빛고급90
5노을(null)85
6새벽중급80
SELECT 이름, 점수
  FROM 수강생
 ORDER BY CASE 레벨 WHEN '고급' THEN 1
                   WHEN '중급' THEN 2
                   ELSE 3 END,
          점수 DESC, 이름;
1
이름점수
별빛90
보람70
새벽80
하늘80
구름95
노을85
2
이름점수
구름95
별빛90
노을85
새벽80
하늘80
보람70
3
이름점수
별빛90
보람70
하늘80
새벽80
구름95
노을85
4
이름점수
보람70
별빛90
새벽80
하늘80
노을85
구름95
정답 및 해설

첫 정렬 키가 CASE 식이라 고급(1), 중급(2), 나머지(3) 순으로 묶이고, 레벨이 NULL 인 노을도 ELSE 로 3 이 되어 초급 구름과 함께 맨 뒤에 온다.

같은 묶음 안에서는 점수 DESC, 점수가 같은 새벽·하늘은 이름 오름차순으로 정렬되며 SELECT 목록에 없는 레벨도 정렬 키로 쓸 수 있다.

  • 점수를 오름차순으로 보면 보람이 별빛보다 앞서게 된다.
  • 동점에서 이름 오름차순이면 새벽이 하늘보다 먼저 온다.
  • CASE 키를 무시하고 점수만 보면 구름이 맨 앞에 오게 된다.
문제 23
다음 SQL을 실행했을 때 결과 행의 수는?

[수강생]

학번이름
S1민지
S2도윤
S3서연

[강좌]

강좌번호강좌명
C1영어
C2수학

[수강신청]

신청번호학번강좌번호
1S1C1
2S1C2
3S2C1
4S3C3
5(null)C2
6S2C2
SELECT S.이름, C.강좌명
  FROM 수강생 S, 수강신청 R, 강좌 C
 WHERE S.학번 = R.학번
   AND R.강좌번호 = C.강좌번호
 ORDER BY R.신청번호;
14
23
36
45
정답 및 해설

세 테이블을 조인하려면 N-1=2개의 조인 조건이 필요하고, 두 조건을 모두 만족하는 신청 1·2·3·6 만 남아 4행이다.

신청 4 는 강좌 C3 이 없어서, 신청 5 는 학번이 NULL 이라서 등가 조인에서 짝을 찾지 못해 빠진다.

  • 3행은 수강생 수로 센 것인데 한 수강생의 여러 신청은 각각 행이 된다.
  • 5행은 NULL 학번 신청까지 넣은 것이며 NULL 은 어떤 값과도 같지 않다.
  • 6행은 수강신청 전체 건수로 짝 없는 신청까지 센 것이다.
문제 24
다음 SQL의 실행 결과에 대한 설명으로 옳은 것은?

[강좌]

강좌번호강좌명선수강좌번호
C1기초영어(null)
C2중급영어C1
C3고급영어C2
C4기초수학(null)
C5토론영어C2
SELECT A.강좌명 AS 강좌, B.강좌명 AS 선수강좌
  FROM 강좌 A
  JOIN 강좌 B ON A.선수강좌번호 = B.강좌번호
 ORDER BY A.강좌번호;
1고급영어의 선수강좌는 기초영어로 나온다
2선수강좌가 있는 강좌만 3행 출력된다
3기초영어가 강좌 열에 한 번 나온다
4중급영어는 선수강좌 열에 한 번 나온다
정답 및 해설

A 는 강좌, B 는 선수강좌 역할을 하는 셀프 조인으로, 선수강좌번호가 NULL 인 기초영어·기초수학은 INNER JOIN 에서 짝이 없어 빠지고 3행만 나온다.

결과는 중급영어-기초영어, 고급영어-중급영어, 토론영어-중급영어이며 한 번의 조인은 바로 위 단계만 연결한다.

  • 기초영어는 선수강좌가 없어 강좌 열에는 나오지 않는다.
  • 중급영어는 고급영어와 토론영어의 선수강좌라 두 번 나온다.
  • 고급영어의 선수강좌는 바로 위 단계인 중급영어다.
문제 25
다음 SQL의 실행 결과로 옳은 것은?

[강사]

강사번호강사명지점코드
T1김하준B1
T2이서윤B2
T3박도현(null)
T4최지아B9

[지점]

지점코드지점명
B1강남
B2분당
B3일산
SELECT *
  FROM 강사 NATURAL JOIN 지점
 ORDER BY 강사번호;
1
지점코드강사번호강사명지점명
B1T1김하준강남
B2T2이서윤분당
(null)T3박도현(null)
B9T4최지아(null)
2
강사번호강사명지점코드지점명
T1김하준B1강남
T2이서윤B2분당
3
지점코드강사번호강사명지점명
B1T1김하준강남
B2T2이서윤분당
4
지점코드강사번호강사명지점코드지점명
B1T1김하준B1강남
B2T2이서윤B2분당
정답 및 해설

NATURAL JOIN 은 이름이 같은 지점코드로 등가 조인하고, SELECT * 에서 공통 열을 한 번만 맨 앞에 둔 뒤 강사와 지점의 나머지 열을 차례로 보여 준다.

지점코드가 NULL 인 T3 과 지점에 없는 B9 를 가진 T4 는 짝이 없어 빠지므로 결과는 2행이다.

  • NATURAL JOIN 은 내부 조인이라 짝 없는 T3·T4 를 NULL 로 남기지 않는다.
  • 공통 열은 왼쪽 테이블의 원래 위치가 아니라 결과 맨 앞에 온다.
  • 공통 열은 하나로 합쳐지므로 지점코드가 두 번 나오지 않는다.
문제 26
Oracle 기준으로 다음 ㉠의 결과 행 수와 ㉡의 결과 값을 순서대로 나열한 것은?

[강좌]

강좌번호강좌명
1국어
2수학
3영어

[수강신청]

학생번호강좌번호
1011
1021
1032
1044
105(null)

㉠

SELECT R.학생번호, C.강좌명
  FROM 강좌 C, 수강신청 R
 WHERE C.강좌번호(+) = R.강좌번호;

㉡

SELECT COUNT(*)
  FROM 강좌 C CROSS JOIN 수강신청 R
 WHERE C.강좌번호 <> R.강좌번호;
13, 12
25, 9
35, 12
44, 9
정답 및 해설

㉠은 (+) 가 강좌 쪽에 붙어 수강신청이 기준인 외부 조인(수강신청 LEFT OUTER JOIN 강좌)이므로 5행이고, ㉡은 CROSS JOIN 15행 중 같은 강좌 3쌍과 NULL 비교 3쌍을 뺀 9이다.

㉠에서 강좌번호가 4 인 신청과 강좌번호가 NULL 인 신청은 강좌명이 NULL 인 채 남고, 신청이 없는 영어는 나오지 않는다.

  • 4, 9 는 (+) 가 붙지 않은 강좌 쪽이 보존된다고 거꾸로 본 결과이다.
  • 5, 12 는 NULL 과의 <> 비교를 참으로 본 경우로, 결과는 UNKNOWN 이라 빠진다.
  • 3, 12 는 ㉠을 등가 조인으로 본 데다 NULL 비교까지 참으로 셈한 결과이다.
문제 27
다음 결과를 얻기 위해 ( ㉠ )에 들어갈 조인 구문으로 옳은 것은?

[강사]

강사번호이름
1윤서
2도현
3하린
4지안

[강좌]

강좌번호강좌명강사번호
10문학1
20미적분2
30회화1
40논술(null)
50물리5
SELECT T.이름, C.강좌명
  FROM 강사 T
  ( ㉠ ) 강좌 C
    ON T.강사번호 = C.강사번호
 WHERE T.강사번호 IS NULL
    OR C.강사번호 IS NULL
 ORDER BY T.이름, C.강좌명;
이름강좌명
지안(null)
하린(null)
(null)논술
(null)물리
1LEFT OUTER JOIN
2INNER JOIN
3RIGHT OUTER JOIN
4FULL OUTER JOIN
정답 및 해설

결과에 강좌가 없는 강사(하린·지안)와 강사가 연결되지 않은 강좌(논술·물리)가 함께 있으므로 양쪽 행을 모두 보존하는 FULL OUTER JOIN 이다.

조인 뒤 WHERE 의 IS NULL 조건은 짝을 찾은 문학·미적분·회화 행을 버리고, 한쪽 열이 NULL 로 채워진 행만 남긴다.

  • LEFT OUTER JOIN 은 강사 쪽만 보존해 하린·지안 2행만 남는다.
  • RIGHT OUTER JOIN 은 강좌 쪽만 보존해 논술·물리 2행만 남는다.
  • INNER JOIN 은 짝이 맞는 행만 만들어 WHERE 를 거치면 0행이다.
문제 28
다음 SQL 의 실행 결과로 옳은 것은?

[수강생]

학생번호이름
1민준
2서연
3지호
4하은

[수강신청]

학생번호강좌번호점수
11085
12092
210(null)
33070
310(null)
SELECT S.이름,
       (SELECT COUNT(*) FROM 수강신청 R
         WHERE R.학생번호 = S.학생번호) AS 신청수,
       (SELECT MAX(R.점수) FROM 수강신청 R
         WHERE R.학생번호 = S.학생번호) AS 최고점
  FROM 수강생 S
 ORDER BY S.학생번호;
1
이름신청수최고점
민준292
서연1(null)
지호270
하은0(null)
2
이름신청수최고점
민준292
서연1(null)
지호270
3
이름신청수최고점
민준292
서연1(null)
지호270
하은(null)(null)
4
이름신청수최고점
민준292
서연0(null)
지호170
하은0(null)
정답 및 해설

SELECT 절의 스칼라 서브쿼리는 수강생 한 행마다 한 값을 돌려주므로 4행이 모두 나오고, 신청이 없는 하은은 COUNT(*) 가 0, MAX 는 NULL 이다.

COUNT(*) 는 점수가 NULL 인 신청 행도 세므로 서연 1·지호 2 이고, MAX 는 NULL 을 빼고 계산해 서연은 NULL, 지호는 70 이다.

  • 하은의 신청수를 NULL 로 본 표는 대상 행이 없을 때 COUNT 도 NULL 이라고 오해한 것이다.
  • 하은이 빠진 표는 스칼라 서브쿼리를 내부 조인처럼 본 결과이다.
  • 서연 0·지호 1 인 표는 COUNT(*) 를 COUNT(점수)처럼 NULL 을 빼고 센 결과이다.
문제 29
신청 내역이 한 건도 없는 수강생을 다음 결과처럼 조회하려고 한다. ( ㉠ )에 들어갈 조건으로 옳은 것은?

[수강생]

학생번호이름
1민준
2서연
3지호
4하은
5도윤

[수강신청]

학생번호강좌번호점수
11080
220(null)
31075
(null)2090
SELECT S.이름
  FROM 수강생 S
 WHERE S.학생번호 NOT IN (SELECT R.학생번호
                            FROM 수강신청 R
                          ( ㉠ ))
 ORDER BY S.이름;
이름
도윤
하은
1WHERE R.강좌번호 = 10
2WHERE R.점수 >= 70
3WHERE R.학생번호 <> NULL
4WHERE R.학생번호 IS NOT NULL
정답 및 해설

서브쿼리 결과에 NULL 이 하나라도 있으면 NOT IN 은 모든 행에서 UNKNOWN 이 되어 0행이므로, 서브쿼리에서 IS NOT NULL 로 NULL 을 걸러야 하은·도윤이 나온다.

걸러진 서브쿼리 결과는 1·2·3 이고, 여기에 없는 학생번호 4·5 만 조건을 만족한다.

  • NULL 과의 <> 비교는 늘 UNKNOWN 이라 서브쿼리가 빈 집합이 되어 다섯 명이 모두 나온다.
  • 점수 70 이상 조건은 학생번호가 NULL 인 신청 행을 남겨 결과가 0행이 된다.
  • 강좌 10 조건은 1·3 만 돌려주어 서연까지 결과에 포함된다.
문제 30
다중행 서브쿼리 연산자에 대한 설명으로 옳은 것은?
1EXISTS 는 반환된 값을 서로 비교한다
2IN 서브쿼리는 한 행만 돌려줘야 한다
3= 연산자로 여러 행과 비교할 수 있다
4= ANY 는 IN 과 같은 결과를 낸다
정답 및 해설

= ANY 는 서브쿼리 결과 중 하나라도 같으면 참이므로 IN 과 같은 결과를 낸다.

다중행 서브쿼리에는 IN·ANY·ALL·EXISTS 같은 다중행 연산자를 쓰고, =·> 같은 단일행 연산자는 한 행만 돌려받아야 한다.

  • EXISTS 는 값을 비교하지 않고 서브쿼리 결과 행이 있는지만 확인한다.
  • 단일행 연산자 = 에 여러 행이 돌아오면 실행 오류가 난다.
  • IN 은 여러 행을 받는 다중행 연산자라 행 수 제한이 없다.
문제 31
다음 SQL 의 실행 결과로 옳은 것은?

[봄학기]

과목
국어
수학
수학

[여름학기]

과목
수학
영어

[특강]

과목
영어
과학
SELECT 과목 FROM 봄학기
UNION ALL
SELECT 과목 FROM 여름학기
UNION
SELECT 과목 FROM 특강
 ORDER BY 과목;
1
과목
국어
수학
영어
과학
2
과목
과학
국어
수학
수학
수학
영어
3
과목
과학
국어
수학
영어
4
과목
과학
국어
수학
수학
영어
정답 및 해설

집합 연산자는 왼쪽부터 차례로 계산되므로 봄학기와 여름학기를 UNION ALL 한 5행 전체가 마지막 UNION 의 입력이 되어 중복이 모두 제거된다.

남는 과목은 과학·국어·수학·영어 4개이고, 맨 끝 ORDER BY 가 전체 결과를 가나다순으로 정렬한다.

  • 수학 3행이 남은 표는 UNION 이 특강과 겹치는 영어만 제거한다고 본 결과이다.
  • 수학 2행이 남은 표는 봄학기 안의 중복은 UNION ALL 이라 보존된다고 본 결과이다.
  • 입력 순서대로 나온 표는 ORDER BY 가 마지막 SELECT 에만 적용된다고 오해한 것이다.
문제 32
Oracle 기준으로 다음 두 테이블의 집합 연산 결과에 대한 설명으로 옳은 것은?

[오전반]

과목
국어
수학
영어
영어

[오후반]

과목
수학
과학
1INTERSECT 결과는 수학과 영어이다
2MINUS 결과에는 중복 행이 남는다
3MINUS 는 두 테이블 순서와 무관하다
4오전반 MINUS 오후반 결과는 2행이다
정답 및 해설

오전반 MINUS 오후반은 오후반에 없는 국어·영어를 남기고 중복을 제거하므로 2행이다.

순서를 바꾼 오후반 MINUS 오전반은 과학 1행이며, 두 테이블의 INTERSECT 는 양쪽에 모두 있는 수학 1행이다.

  • MINUS 는 앞 집합에서 뒤 집합을 빼므로 순서를 바꾸면 결과가 달라진다.
  • 영어는 오후반에 없어 교집합에 들어가지 못한다.
  • MINUS 는 UNION 처럼 중복을 제거해 영어가 한 번만 나온다.
문제 33
다음 SQL 의 실행 결과로 옳은 것은?

[반편성]

과목반인원
수학A10
수학B8
영어A12
영어(null)5
SELECT 과목, 반, SUM(인원) AS 합계,
       GROUPING(반) AS G
  FROM 반편성
 GROUP BY GROUPING SETS ((과목, 반), 과목)
 ORDER BY 과목, G, 반;
1
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)51
영어(null)171
2
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)50
영어(null)171
3
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)171
4
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)50
영어(null)171
(null)(null)351
정답 및 해설

GROUPING SETS 에 적은 (과목, 반) 상세 4행과 과목 소계 2행만 만들어지며, 총계 행은 없다.

영어·NULL·5 는 원래 반이 NULL 인 상세 행이라 GROUPING(반)=0 이고, 소계 행의 NULL 만 집계로 생겨 1 이다.

  • 영어·NULL·5 의 G 를 1 로 본 표는 NULL 이면 모두 소계라고 오해한 것이다.
  • 영어·NULL·5 가 빠진 표는 NULL 반 상세 행을 소계와 합쳐 버린 결과이다.
  • 총계 35 행이 있는 표는 빈 그룹 () 을 적지 않았는데도 총계가 생긴다고 본 것이다.
문제 34
다음 SQL 의 실행 결과로 옳은 것은?

[시간표]

요일과목수강생수
월국어20
월수학15
화수학25
SELECT 요일, 과목, SUM(수강생수) AS 합계
  FROM 시간표
 GROUP BY ROLLUP (요일, 과목)
 ORDER BY 요일, 과목;
1
요일과목합계
월국어20
월수학15
화수학25
(null)국어20
(null)수학40
(null)(null)60
2
요일과목합계
월국어20
월수학15
월(null)35
화수학25
화(null)25
(null)(null)60
3
요일과목합계
월국어20
월수학15
월(null)35
화수학25
화(null)25
4
요일과목합계
월국어20
월수학15
월(null)35
화수학25
화(null)25
(null)국어20
(null)수학40
(null)(null)60
정답 및 해설

ROLLUP (요일, 과목) 은 (요일, 과목) 상세 → 요일별 소계 → 총계 순으로 집계하므로 상세 3행·소계 2행·총계 1행의 6행이다.

소계 행은 과목이 NULL 이고 ASC 정렬에서 NULL 이 뒤로 가므로 각 요일 상세 다음에, 총계 60 은 맨 끝에 온다.

  • 과목별 소계만 있는 표는 인수 순서를 바꾼 ROLLUP (과목, 요일) 의 결과이다.
  • 총계가 없는 표는 GROUP BY 요일, ROLLUP (과목) 처럼 부분 ROLLUP 일 때의 결과이다.
  • 요일·과목 소계를 모두 가진 표는 CUBE 의 결과이다.
문제 35
다음 결과를 얻기 위해 ( ㉠ )에 들어갈 구문으로 옳은 것은?

[강의매출]

강사과목매출
윤서국어30
윤서논술20
도현국어40
하린수학50
하린국어10
SELECT 강사, 과목, SUM(매출) AS 매출합
  FROM 강의매출
 GROUP BY ( ㉠ )
 ORDER BY 강사, GROUPING(과목), 과목;
강사과목매출합
도현국어40
도현(null)40
윤서국어30
윤서논술20
윤서(null)50
하린국어10
하린수학50
하린(null)60
1강사, ROLLUP (과목)
2ROLLUP (강사, 과목)
3CUBE (강사, 과목)
4GROUPING SETS (강사, 과목)
정답 및 해설

결과는 상세 5행과 강사별 소계 3행으로 8행이며 총계 행이 없으므로, 강사는 고정하고 과목만 ROLLUP 하는 부분 ROLLUP 인 강사, ROLLUP (과목) 이다.

부분 ROLLUP 은 괄호 밖 열을 모든 그룹에 붙이므로 강사가 NULL 인 총계 행이 생기지 않는다.

  • ROLLUP (강사, 과목) 은 끝에 총계 1행이 더해져 9행이 된다.
  • CUBE 는 과목별 소계와 총계까지 만들어 12행이 된다.
  • GROUPING SETS (강사, 과목) 은 상세 행 없이 강사별·과목별 집계 6행만 만든다.
문제 36
학생마다 결제일 순서로 금액을 누적한 다음 결과를 얻으려고 한다. ( ㉠ )에 들어갈 구문으로 옳은 것은?

[수강결제]

학생번호결제일금액
12026-03-02100
22026-03-03200
12026-03-05150
22026-03-0750
12026-03-09120
SELECT 학생번호, 결제일,
       SUM(금액) OVER (( ㉠ )) AS 누적액
  FROM 수강결제
 ORDER BY 학생번호, 결제일;
학생번호결제일누적액
12026-03-02100
12026-03-05250
12026-03-09370
22026-03-03200
22026-03-07250
1PARTITION BY 학생번호
2PARTITION BY 결제일
3ORDER BY 학생번호, 결제일
4PARTITION BY 학생번호 ORDER BY 결제일
정답 및 해설

학생번호가 바뀔 때마다 누적액이 처음부터 다시 쌓이고 결제일 순으로 늘어나므로 PARTITION BY 학생번호 와 ORDER BY 결제일 이 함께 있어야 한다.

학생 1 은 100·250·370, 학생 2 는 200·250 으로 파티션 안에서 현재 행까지 더한다.

  • ORDER BY 학생번호, 결제일 만 주면 파티션이 없어 학생 2 의 첫 값이 570 으로 이어진다.
  • PARTITION BY 학생번호 만 주면 누적이 아니라 학생별 합계 370·250 이 모든 행에 나온다.
  • PARTITION BY 결제일 은 날짜마다 파티션이 따로 생겨 각 행의 금액만 나온다.
문제 37
다음 SQL 의 실행 결과로 옳은 것은?

[모의평가]

학생회차점수
민준170
민준285
민준380
서연190
서연295
SELECT 학생, 회차,
       FIRST_VALUE(점수) OVER (PARTITION BY 학생 ORDER BY 회차
         ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS A,
       LAST_VALUE(점수) OVER (PARTITION BY 학생 ORDER BY 회차
         ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS B
  FROM 모의평가
 ORDER BY 학생, 회차;
1
학생회차AB
민준17085
민준27080
민준37080
서연19095
서연29095
2
학생회차AB
민준1(null)85
민준27080
민준38580
서연1(null)95
서연29095
3
학생회차AB
민준17085
민준27080
민준385(null)
서연19095
서연290(null)
4
학생회차AB
민준17085
민준27080
민준38580
서연19095
서연29095
정답 및 해설

A 는 직전 행~현재 행 프레임의 첫 값, B 는 현재 행~다음 행 프레임의 끝 값이므로 민준 3회차는 A=85·B=80 이 된다.

파티션 첫 행은 프레임에 자기 자신만 있어 A 가 자기 점수이고, 마지막 행도 B 가 자기 점수라서 NULL 이 생기지 않는다.

  • 첫 행 A 가 NULL 인 표는 FIRST_VALUE 를 LAG 처럼 본 결과이다.
  • 마지막 행 B 가 NULL 인 표는 LAST_VALUE 를 LEAD 처럼 본 결과이다.
  • 민준 3회차 A 가 70 인 표는 프레임을 무시하고 파티션 첫 값을 쓴 결과이다.
문제 38
Oracle 기준으로 다음 SQL 을 실행했을 때 수학 행의 R 과 C 값을 순서대로 나열한 것은?

[강좌현황]

강좌수강생수
국어20
수학30
영어40
과학10
SELECT 강좌,
       RATIO_TO_REPORT(수강생수) OVER () AS R,
       CUME_DIST() OVER (ORDER BY 수강생수) AS C
  FROM 강좌현황;
130, 0.75
20.75, 0.3
30.3, 0.75
40.3, 0.67
정답 및 해설

RATIO_TO_REPORT 는 전체 합 100 에 대한 비율이라 30/100=0.3 이고, CUME_DIST 는 수학 이하 값을 가진 3행을 전체 4행으로 나눠 0.75 이다.

CUME_DIST 는 현재 행을 포함한 누적 비율이라 마지막 행이 1 이 되며, (순위-1)/(행수-1) 로 계산하는 PERCENT_RANK 와 구별한다.

  • 0.67 은 PERCENT_RANK 공식 (3-1)/(4-1) 로 계산한 값이다.
  • 30 은 비율이 아니라 백분율로 착각한 값으로, 결과는 0~1 사이 소수이다.
  • 두 값의 순서를 서로 바꾼 조합이다.
문제 39
다음 SQL 의 결과 행 수와 전체 열의 값을 순서대로 나열한 것은?

[수강]

학생번호과목
1국어
2국어
3국어
4수학
5수학
6영어
7영어
8(null)
SELECT 과목, COUNT(*) AS 인원,
       SUM(COUNT(*)) OVER () AS 전체
  FROM 수강
 GROUP BY 과목;
13, 7
24, 8
38, 8
44, 4
정답 및 해설

윈도우 함수는 GROUP BY 가 끝난 뒤 그룹 행에 적용되므로 결과는 국어·수학·영어·NULL 의 4행이고, 각 그룹 인원 3·2·2·1 을 모두 더한 전체는 8 이다.

과목이 NULL 인 행도 하나의 그룹이 되며 COUNT(*) 는 그 행을 1 로 센다.

  • 8행은 윈도우 함수가 원본 행 수를 유지한다고 보고 GROUP BY 를 무시한 것이다.
  • 3행·7 은 NULL 그룹을 버린 결과로, GROUP BY 는 NULL 도 그룹으로 만든다.
  • 전체 4 는 SUM 이 그룹 개수를 센다고 본 값으로, 실제로는 인원을 더한다.
문제 40
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[성적]

이름점수
민준88
서연95
지호72
하은91
도윤88
유나60
SELECT 이름, 점수
  FROM (SELECT 이름, 점수
          FROM 성적
         ORDER BY 점수 DESC, 이름)
 WHERE ROWNUM <= 3
 ORDER BY 이름;
1
이름점수
도윤88
민준88
서연95
하은91
2
이름점수
서연95
하은91
도윤88
3
이름점수
도윤88
서연95
하은91
4
이름점수
도윤88
민준88
서연95
정답 및 해설

인라인 뷰가 점수 내림차순(동점은 이름순)으로 서연·하은·도윤·민준… 을 만든 뒤 ROWNUM <= 3 이 앞의 세 행을 자르고, 바깥 ORDER BY 이름 이 그 3행만 다시 정렬한다.

동점 88 인 도윤과 민준 중 이름순으로 앞선 도윤만 3위 안에 들어간다.

  • 도윤·민준·서연 표는 바깥 ORDER BY 가 ROWNUM 보다 먼저 적용된다고 본 결과이다.
  • 4행 표는 동점을 모두 포함하는 WITH TIES 처럼 본 것으로, ROWNUM 은 정확히 3행에서 멈춘다.
  • 점수순으로 나온 표는 바깥 ORDER BY 이름을 무시한 결과이다.
문제 41
Oracle(12c 이상)에서 다음 SQL 의 ( ㉠ ) 자리에 넣었을 때 오류가 발생하는 것은?
SELECT 이름, 점수
  FROM 성적
 ORDER BY 점수 DESC
( ㉠ );
1FETCH FIRST 50 PERCENT ROWS ONLY
2OFFSET 3 FETCH NEXT 3 ROWS ONLY
3FETCH NEXT 3 ROWS WITH TIES
4FETCH FIRST ROW ONLY
정답 및 해설

Oracle 의 행 제한절에서 OFFSET n 뒤에는 ROW 또는 ROWS 키워드가 반드시 와야 하므로 ROWS 가 빠진 구문은 오류이다.

FETCH 절도 건수 뒤에 ROW·ROWS 와 함께 ONLY 또는 WITH TIES 를 적어야 하며, 건수는 생략하면 1행으로 처리된다.

  • FETCH FIRST ROW ONLY 는 건수를 생략한 형태로 첫 1행을 돌려준다.
  • WITH TIES 는 ORDER BY 가 있으므로 3번째 점수와 같은 동점 행까지 포함한다.
  • PERCENT 는 전체 행 중 지정 비율만큼을 돌려주는 올바른 구문이다.
문제 42
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[강사]

강사번호이름멘토번호
1가온3
2나래1
3다솜2
4라온1
SELECT 이름, LEVEL AS LV,
       CONNECT_BY_ISCYCLE AS CYC
  FROM 강사
 START WITH 강사번호 = 1
CONNECT BY NOCYCLE PRIOR 강사번호 = 멘토번호
 ORDER SIBLINGS BY 이름;
1
이름LVCYC
가온11
나래20
다솜30
라온20
2
이름LVCYC
가온10
나래20
다솜31
라온20
3
이름LVCYC
가온10
나래20
다솜30
가온41
라온20
4
이름LVCYC
가온10
나래20
다솜30
라온20
정답 및 해설

가온의 멘토가 다솜이라 다솜 아래에 가온이 다시 이어지는 순환이 있지만, NOCYCLE 은 이미 지나온 가온을 다시 전개하지 않아 4행에서 멈춘다.

CONNECT_BY_ISCYCLE 은 자식이 자기 조상인 행에서 1 이므로, 자식 가온이 조상인 다솜만 1 이다.

  • 루트 가온에 1 을 준 표는 순환 대상 행 자체에 표시된다고 오해한 것이다.
  • 가온이 LEVEL 4 로 한 번 더 나온 표는 반복 행을 한 번 출력한 뒤 멈춘다고 본 결과이다.
  • 모두 0 인 표는 NOCYCLE 로 전개가 끊기면 순환 표시도 없다고 본 것이다.
문제 43
다음 SQL 에 대한 설명으로 옳은 것은?

[강사]

강사번호이름멘토번호
1가온(null)
2나래1
3다솜1
4라온2
SELECT A.이름 AS 강사, B.이름 AS 멘토
  FROM 강사 A
  LEFT OUTER JOIN 강사 B
    ON A.멘토번호 = B.강사번호;
1결과 행 수는 강사 수 4와 같다
2멘토가 없는 가온은 결과에서 빠진다
3멘토 열에는 부하의 이름이 나온다
4별칭을 빼도 같은 결과가 나온다
정답 및 해설

셀프 조인을 LEFT OUTER JOIN 으로 했으므로 A 쪽 강사 4명이 모두 남고, 각 강사의 멘토는 많아야 한 명이라 결과는 강사 수와 같은 4행이다.

가온은 멘토번호가 NULL 이라 짝이 없지만 멘토 열이 NULL 인 채로 결과에 나온다.

  • INNER JOIN 이었다면 가온이 빠지지만 외부 조인이라 보존된다.
  • B 는 A 의 멘토번호와 강사번호가 같은 행이므로 멘토(상위자)의 이름이다.
  • 같은 테이블을 두 번 쓰므로 별칭이 없으면 열을 구분할 수 없어 오류가 난다.
문제 44
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[출석]

반강사요일인원
A윤서월10
A윤서화12
A도현월8
B하린월15
B하린화5
SELECT *
  FROM 출석
 PIVOT (SUM(인원) FOR 요일 IN ('월' AS 월, '화' AS 화))
 ORDER BY 반, 강사;
1
반월화
A1812
B155
2
반강사월화
A도현8(null)
A윤서10(null)
A윤서(null)12
B하린15(null)
B하린(null)5
3
반강사월화
A도현8(null)
A윤서1012
B하린155
4
반강사월화
A도현80
A윤서1012
B하린155
정답 및 해설

PIVOT 은 집계 열(인원)과 FOR 열(요일)을 뺀 나머지 열 반·강사를 모두 그룹 기준으로 삼으므로 (A, 도현)·(A, 윤서)·(B, 하린)의 3행이 된다.

도현은 화요일 데이터가 없어 화 열이 0 이 아닌 NULL 이며, 같은 그룹의 월·화 값은 한 행으로 합쳐진다.

  • 반별 2행 표는 강사 열도 그룹 기준이 된다는 점을 놓친 결과로, 인라인 뷰로 강사를 빼야 나온다.
  • 도현의 화를 0 으로 본 표는 값이 없는 칸이 NULL 이라는 점을 놓친 것이다.
  • 원본 5행이 그대로 남은 표는 PIVOT 이 그룹별로 행을 합친다는 점을 무시한 결과이다.
문제 45
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[강좌코드]

번호코드
1MATH-101
2MATH101
3ENG-20
4KOR-1001
5SCI--10
6math-102
SELECT 번호, 코드
  FROM 강좌코드
 WHERE REGEXP_LIKE(코드, '^[A-Z]{3,4}-?[0-9]{2,3}$')
 ORDER BY 번호;
1
번호코드
1MATH-101
2MATH101
3ENG-20
2
번호코드
1MATH-101
3ENG-20
3
번호코드
1MATH-101
2MATH101
3ENG-20
4KOR-1001
4
번호코드
1MATH-101
2MATH101
3ENG-20
6math-102
정답 및 해설

패턴은 대문자 3~4개, 하이픈 0~1개(?), 숫자 2~3개({2,3}) 로 문자열 전체가 이루어져야 하므로 번호 1~3 의 행만 일치한다.

KOR-1001 은 숫자가 4개라 $ 앞에서 어긋나고, SCI--10 은 하이픈이 2개, math-102 는 소문자라 [A-Z] 에 맞지 않는다.

  • KOR-1001 을 넣은 표는 {2,3} 을 2회 이상으로 보거나 $ 앵커를 무시한 결과이다.
  • MATH101 을 뺀 표는 ? 를 정확히 1회로 오해한 결과이다.
  • math-102 를 넣은 표는 기본 매칭이 대소문자를 구분한다는 점을 놓친 것이다.
문제 46
수료자 테이블에 유나 1행이 들어 있는 상태에서 다음 INSERT 문을 실행했을 때, 수료자 테이블의 전체 행 수는?

[수강생]

학생번호이름출석률
1민준95
2서연80
3지호(null)
4하은79
5도윤88
INSERT INTO 수료자 (학생번호, 이름)
SELECT 학생번호, 이름
  FROM 수강생
 WHERE 출석률 >= 80;
15
26
34
43
정답 및 해설

INSERT … SELECT 는 서브쿼리가 돌려준 행을 모두 한 번에 넣으므로 출석률 80 이상인 민준·서연·도윤 3행이 추가되어 기존 1행과 합쳐 4행이다.

80 은 >= 조건에 포함되고, 출석률이 NULL 인 지호는 비교 결과가 UNKNOWN 이라 들어가지 않는다.

  • 3 은 기존 유나 행이 지워지고 새로 채워진다고 본 값이다.
  • 5 는 출석률이 NULL 인 지호까지 넣은 값이다.
  • 6 은 WHERE 조건을 무시하고 수강생 전원을 넣은 값이다.
문제 47
Oracle 에서 수강생 테이블에 INSERT 를 하고 COMMIT 을 하지 않은 상태다. 이어서 일어난 일 중 그 INSERT 가 자동으로 확정되지 않는 경우는?
1CREATE TABLE 문을 실행했다
2GRANT 문을 실행했다
3SQL*Plus 를 EXIT 로 끝냈다
4정전으로 세션이 끊겼다
정답 및 해설

정전·장애로 세션이 비정상 종료되면 Oracle 은 커밋되지 않은 변경을 자동으로 ROLLBACK 하므로 INSERT 는 사라진다.

반대로 DDL·DCL 문은 실행 전후에 암시적 COMMIT 이 일어나고, 도구를 정상 종료할 때도 기본 설정에서 COMMIT 된다.

  • CREATE TABLE 은 DDL 이라 앞선 INSERT 가 함께 확정된다.
  • GRANT 는 DCL 이라 실행 시 앞선 INSERT 가 확정된다.
  • SQL*Plus 의 EXIT 정상 종료는 기본적으로 COMMIT 후 끝낸다.
문제 48
다음과 같이 정의된 테이블에서 강좌 10 에 대한 수강신청이 있고, 그 신청에 대한 출석 기록도 있다. DELETE 문 실행 결과에 대한 설명으로 옳은 것은?
CREATE TABLE 수강신청 (
  신청번호 INT PRIMARY KEY,
  강좌번호 INT REFERENCES 강좌(강좌번호)
           ON DELETE CASCADE
);
CREATE TABLE 출석 (
  출석번호 INT PRIMARY KEY,
  신청번호 INT REFERENCES 수강신청(신청번호)
);

DELETE FROM 강좌 WHERE 강좌번호 = 10;
1강좌만 삭제되고 수강신청은 남는다
2출석 기록까지 모두 연쇄 삭제된다
3오류가 나 어떤 행도 삭제되지 않는다
4강좌와 수강신청만 함께 삭제된다
정답 및 해설

강좌 삭제는 ON DELETE CASCADE 로 수강신청 삭제를 부르지만, 그 신청을 출석이 삭제 옵션 없는 기본 FK(제한)로 참조하고 있어 무결성 오류가 난다.

DELETE 문은 한 문장 단위로 처리되므로 연쇄 경로 어디에서든 오류가 나면 강좌·수강신청 모두 삭제되지 않는다.

  • CASCADE 가 지정돼 있어 강좌만 지우고 자식을 남기는 경우는 없다.
  • 수강신청까지 지우면 출석이 사라진 신청을 가리키게 되어 허용되지 않는다.
  • 출석 FK 에는 CASCADE 가 없으므로 출석까지 연쇄 삭제되지 않는다.
문제 49
Oracle 에서 CREATE TABLE 강좌 ( … ) 의 괄호 안에 넣었을 때 오류가 발생하는 열 정의는?
1개강일 DATE DEFAULT SYSDATE
2정원 NUMBER DEFAULT 0
3등급 CHAR DEFAULT 'A'
4강좌명 VARCHAR2 NOT NULL
정답 및 해설

Oracle 의 VARCHAR2 는 가변 길이 문자형이라 최대 길이를 VARCHAR2(30) 처럼 반드시 지정해야 하므로 길이가 빠진 정의는 오류이다.

반면 CHAR 는 길이를 생략하면 1, NUMBER 는 정밀도를 생략하면 최대 정밀도로 정의되어 실행된다.

  • 정원 정의는 정밀도 없는 NUMBER 에 기본값 0 을 준 올바른 구문이다.
  • 등급 정의는 길이 1 인 CHAR 에 한 글자 기본값을 준 올바른 구문이다.
  • 개강일 정의는 DATE 에 현재 일시 SYSDATE 를 기본값으로 준 올바른 구문이다.
문제 50
Oracle 에서 DBA 가 다음을 순서대로 실행했다(㉡·㉣은 강사A 가 실행). 실행 후 상태에 대한 설명으로 옳은 것은?
㉠ GRANT CREATE TABLE TO 강사A WITH ADMIN OPTION;
㉡ GRANT CREATE TABLE TO 조교B;
㉢ GRANT SELECT ON 성적 TO 강사A WITH GRANT OPTION;
㉣ GRANT SELECT ON 성적 TO 조교B;
㉤ REVOKE CREATE TABLE FROM 강사A;
㉥ REVOKE SELECT ON 성적 FROM 강사A;
1조교B 의 CREATE TABLE 은 남는다
2시스템 권한도 GRANT OPTION 을 쓴다
3조교B 는 성적을 계속 조회한다
4강사A 는 테이블을 계속 만든다
정답 및 해설

WITH ADMIN OPTION 으로 받은 시스템 권한은 강사A 에게서 회수해도 강사A 가 조교B 에게 준 권한이 연쇄 회수되지 않으므로 조교B 의 CREATE TABLE 은 남는다.

반면 WITH GRANT OPTION 으로 받은 객체 권한 SELECT 는 회수 시 강사A 가 넘겨준 조교B 의 권한까지 함께 회수된다.

  • 객체 권한 회수는 연쇄되므로 조교B 도 성적을 조회할 수 없다.
  • 시스템 권한의 재부여 옵션은 WITH ADMIN OPTION 이고 GRANT OPTION 은 객체 권한용이다.
  • 강사A 는 CREATE TABLE 이 회수되어 더 이상 테이블을 만들 수 없다.
SQLD SQL 개발자 실전 모의고사모두CBT · moducbt.com
SQL 개발자 기출유형 모의고사 7회
총 50문항 · 객관식 · 정답·해설 포함
문제 1
학원 관리 DB에서 수강생 테이블에 인덱스를 추가하고 저장 파일 구조를 바꾸었는데도 개념 스키마와 응용 프로그램은 고칠 필요가 없었다. 이 성질을 무엇이라 하는가?
1물리적 데이터 독립성
2논리적 독립성
3데이터 중복의 최소화
4참조 무결성 보장
정답 및 해설

내부 스키마(저장 구조·인덱스)가 바뀌어도 개념 스키마와 응용 프로그램이 영향을 받지 않는 성질을 물리적 데이터 독립성이라 한다.

개념 스키마가 바뀌어도 외부 스키마와 응용 프로그램이 유지되는 성질은 논리적 데이터 독립성으로 구분한다.

  • 논리적 독립성은 개념 스키마 변경에 대한 성질이라 이 상황과 다르다.
  • 데이터 중복 최소화는 독립성이 아니라 통합 저장의 목적이다.
  • 참조 무결성은 FK 값이 부모 PK 에 존재해야 한다는 제약이다.
문제 2
다음은 학원 업무의 ERD이다. 각 엔터티를 유형·무형과 발생 시점에 따라 분류한 것으로 옳지 않은 것은?

그림

1강사 — 유형·기본 엔터티
2출석 — 사건·중심 엔터티
3과목 — 개념·기본 엔터티
4수강생 — 유형이자 키(기본) 엔터티
정답 및 해설

출석은 수강신청에서 다시 파생되어 매일 쌓이는 데이터이므로 행위 엔터티이며 중심 엔터티가 아니다.

중심 엔터티는 기본 엔터티로부터 생겨 업무의 중심이 되는 엔터티이고, 행위 엔터티는 그 아래에서 다시 파생되어 자주 발생·변경된다.

  • 강사는 물리적 형태가 있고 독립적으로 생성되는 유형·기본 엔터티다.
  • 과목은 형태가 없는 개념이며 다른 엔터티 없이 생기는 기본 엔터티다.
  • 수강생은 실체가 있는 사람이고 다른 엔터티 없이 먼저 존재하는 키(기본) 엔터티다.
문제 3
수강생 한 명이 휴대전화·자택 전화·보호자 전화 등 연락처를 여러 개 가질 수 있다. '연락처' 속성의 설계로 가장 적절한 것은?
1파생 속성이라 계산해서 채워 넣는다
2설계 속성이라 임의 순번을 붙여 관리한다
3다중값 속성이라 별도 엔터티로 나눈다
4복합 속성이라 하위 속성으로 쪼갠다
정답 및 해설

한 인스턴스가 같은 속성에 값을 여러 개 갖는 연락처는 다중값 속성이므로 수강생연락처 같은 별도 엔터티로 분리해 1:N 관계로 연결한다.

속성은 인스턴스마다 하나의 값만 가져야 하며, 한 칸에 여러 번호를 넣으면 제1정규형을 위반한다.

  • 복합 속성은 주소처럼 한 값을 의미 단위로 나누는 경우라 값이 여러 개인 것과 다르다.
  • 파생 속성은 다른 속성에서 계산되는 값이라 연락처와 무관하다.
  • 설계 속성은 업무에 없던 코드·순번을 설계상 새로 만든 속성이다.
문제 4
학원 업무에서 관계를 존재 관계와 행위 관계로 나눌 때, 행위 관계에 해당하는 것은?
1수강생이 강좌를 신청한다
2과목이 한 계열에 속한다
3강사가 한 지점에 소속된다
4강의실이 한 층에 배치된다
정답 및 해설

수강생이 강좌를 신청하는 것처럼 어떤 행위가 일어나야 맺어지는 관계를 행위 관계라 하며, 그 결과가 수강신청 같은 행위 엔터티로 남는다.

소속·배치·포함처럼 한 엔터티의 존재 자체로 다른 엔터티와 연결되는 관계는 존재 관계로 분류한다.

  • 강사의 지점 소속은 행위 없이 존재로 맺어지는 존재 관계다.
  • 강의실의 층 배치는 위치상 포함되는 존재 관계다.
  • 과목의 계열 소속도 분류상 포함되는 존재 관계다.
문제 5
강좌 → 강좌회차 → 회차출석처럼 식별자 관계(실선)만으로 하위 엔터티를 계속 연결할 때 나타나는 현상으로 옳은 것은?
1자식 인스턴스를 부모 없이 먼저 만들 수 있다
2하위로 갈수록 주식별자 속성이 늘어난다
3관계선이 모두 점선으로 그려진다
4부모 식별자가 일반 속성으로 내려간다
정답 및 해설

식별자 관계는 부모 주식별자를 자식 주식별자에 포함하므로 단계가 깊어질수록 상속된 PK 속성이 누적되어 복합키가 커진다.

그 결과 하위 테이블의 조인 조건이 길어지므로 독립 생명주기를 갖는 자식은 비식별자 관계(점선)로 끊는 것을 검토한다.

  • 부모 없이 자식을 먼저 만들 수 있는 것은 비식별자 관계의 특징이다.
  • 부모 식별자가 일반 속성(FK)으로만 내려가는 것은 비식별자 관계다.
  • 점선은 비식별자 관계 표기이며 식별자 관계는 실선이다.
문제 6
[수강내역(수강생번호, 수강생명, 강좌코드, 강좌명, 강사명, 신청일)] 하나로 관리하던 데이터를 다음 ERD처럼 정규화하였다. 이에 대한 설명으로 옳지 않은 것은?

그림

1신청 전에도 강좌를 미리 등록할 수 있다
2모든 조회 질의의 조인 횟수가 줄어든다
3강좌명이 바뀌면 강좌 한 행만 고친다
4수강생별 강좌명 조회에 조인이 필요하다
정답 및 해설

정규화는 중복을 없애 갱신·삽입 이상을 제거하지만 테이블이 나뉘므로 여러 엔터티 정보를 함께 보는 조회에서는 오히려 조인이 늘어난다.

그래서 조회 위주 업무에서는 성능을 위해 반정규화를 검토하기도 한다.

  • 강좌명은 강좌 테이블에만 있으므로 한 행만 수정하면 된다.
  • 강좌를 독립 테이블로 두어 신청 없이도 입력할 수 있다.
  • 수강생별 강좌명은 수강신청과 강좌를 조인해야 얻는다.
문제 7
다음 ERD를 그대로 테이블로 구현하였다. '강좌가 개설된 지점'의 지점명별 수강신청 건수를 구하는 방법으로 옳은 것은?

그림

1수강생의 지점코드를 거쳐 지점과 조인한다
2강좌와 지점만 조인해 건수를 센다
3수강신청과 지점을 지점코드로 바로 조인한다
4수강신청·강좌·지점을 두 조건으로 조인한다
정답 및 해설

비식별자 관계라 수강신청에는 지점코드가 없고 강좌번호만 FK 로 있으므로 수강신청.강좌번호=강좌.강좌번호와 강좌.지점코드=지점.지점코드 두 조건으로 세 테이블을 조인해야 한다.

관계(PK-FK)를 따라 조인하는 것이 원칙이며, 이름이 같은 지점코드라도 어느 관계에서 온 FK 인지 구분해야 한다.

  • 수강신청에는 지점코드 열이 없어 지점과 바로 조인할 수 없다.
  • 수강생의 지점코드는 등록 지점이라 강좌 개설 지점과 다를 수 있다.
  • 강좌와 지점만으로는 강좌 수만 알 뿐 신청 건수를 셀 수 없다.
문제 8
업무 규칙상 수강신청 1건은 1회차 납부 1건과 반드시 함께 등록되어야 한다. 다음 데이터와 작업 기록에 대한 설명으로 옳은 것은?

[수강신청]

신청번호수강생번호신청일
R1S12026-03-02
R2S22026-03-02
R3S12026-03-04

[납부]

신청번호회차금액
R11150000
R21120000
R31150000
R32150000

[작업 기록]

INSERT INTO 수강신청 VALUES ('R4', 'S3', DATE '2026-03-05');
COMMIT;
INSERT INTO 납부 VALUES ('R4', 1, 180000);  -- 제약 위반 오류
ROLLBACK;
1R3은 납부가 두 건이라 규칙을 어겼다
2R4는 신청만 남아 규칙을 어긴 상태다
3두 INSERT 는 따로 커밋해야 한다
4ROLLBACK 으로 R4 신청도 취소된다
정답 및 해설

R4 신청은 이미 COMMIT 으로 확정된 뒤 납부 입력이 실패했으므로 ROLLBACK 을 해도 신청만 남아 함께 등록 규칙을 어긴 상태가 된다.

두 INSERT 를 하나의 트랜잭션으로 묶고 모두 성공한 뒤 한 번만 커밋해야 원자성이 지켜진다.

  • ROLLBACK 은 마지막 COMMIT 이후 작업만 되돌리므로 R4 신청은 남는다.
  • 1회차 납부가 있으면 되므로 납부가 두 건인 R3 은 규칙에 맞다.
  • 따로 커밋하면 한쪽만 저장되는 상태가 생겨 오히려 위험하다.
문제 9
수강생 테이블의 '보호자연락처' 열에 NULL 이 들어 있을 때, NULL 에 대한 설명으로 옳은 것은?
1값이 없거나 미정인 상태를 뜻한다
2COUNT(열)은 NULL 행도 센다
3NULL+숫자는 그 숫자 값이 된다
4NULL 끼리 = 비교하면 참이다
정답 및 해설

NULL 은 0 이나 공백이 아니라 값이 없거나 아직 알 수 없는 상태를 나타내는 표시다.

그래서 NULL 과의 비교는 UNKNOWN, 산술 연산 결과는 NULL 이 되고 집계 함수는 NULL 행을 빼고 계산한다.

  • NULL = NULL 도 UNKNOWN 이므로 참이 아니며 IS NULL 로 판별한다.
  • NULL 이 포함된 산술 연산의 결과는 NULL 이다.
  • COUNT(열)은 NULL 인 행을 세지 않고 COUNT(*)만 모든 행을 센다.
문제 10
수강신청 엔터티의 본질식별자가 (수강생번호+강좌번호+신청일자)이고, 그 아래에 출석·납부·평가 엔터티가 식별자 관계로 연결된다. 인조식별자 '신청번호'를 주식별자로 두는 이유로 가장 적절한 것은?
1하위 엔터티로 상속될 식별자가 단순해진다
2본질식별자의 유니크 제약이 불필요하다
3수강생의 중복 신청을 자동으로 막는다
4식별자만 보고도 업무 의미를 알 수 있다
정답 및 해설

본질식별자가 세 속성의 복합키이면 하위 엔터티마다 모두 상속되어 PK 와 조인 조건이 길어지므로 단일 인조식별자로 바꾸면 상속 식별자가 단순해진다.

대신 인조식별자는 업무 중복을 막지 못하므로 본질식별자 조합에 별도 유니크 제약을 두어야 한다.

  • 순번만으로는 같은 신청의 중복 입력을 막을 수 없다.
  • 업무 의미가 드러나는 쪽은 본질식별자이고 인조식별자는 의미가 없다.
  • 중복 방지를 위해 본질식별자 조합에 유니크 제약이 오히려 필요하다.
문제 11
다음 중 SQL 문의 종류가 나머지 셋과 다른 것은?
1TRUNCATE
2ROLLBACK
3COMMIT
4SAVEPOINT
정답 및 해설

TRUNCATE 는 테이블 구조는 남기고 데이터를 모두 지우는 DDL 로 분류되며 나머지 셋은 트랜잭션을 제어하는 TCL 이다.

TCL 은 COMMIT·ROLLBACK·SAVEPOINT 처럼 DML 작업의 확정과 취소 단위를 다루는 명령이다.

  • COMMIT 은 트랜잭션의 변경을 확정하는 TCL 이다.
  • SAVEPOINT 는 부분 롤백 지점을 지정하는 TCL 이다.
  • ROLLBACK 은 커밋 전 변경을 취소하는 TCL 이다.
문제 12
다음 [강좌] 테이블에 대해 SQL을 실행한 결과로 옳은 것은?

[강좌]

강좌번호과목레벨수강료
1영어A100
2영어A100
3영어B100
4수학A120
5수학A150
6수학A120
SELECT DISTINCT 과목 || 레벨 AS 반,
       수강료 + 20 * 2 AS 금액
  FROM 강좌
 ORDER BY 반, 금액;
1
반금액
수학A160
영어A140
영어B140
2
반금액
수학A280
수학A340
영어A240
영어B240
3
반금액
수학A160
수학A190
영어A140
영어B140
4
반금액
수학A160
수학A160
수학A190
영어A140
영어A140
영어B140
정답 및 해설

곱셈이 덧셈보다 먼저라 금액은 수강료+40이고, DISTINCT 는 SELECT 목록 전체(반, 금액) 조합이 같은 행만 하나로 합친다.

영어A·140 두 행과 수학A·160 두 행이 각각 하나로 줄어 4행이 남고, 금액이 다른 수학A 160·190 은 서로 다른 행이라 모두 남는다.

  • (수강료+20)*2 로 계산하면 금액이 240·280 처럼 커져 우선순위를 어긴다.
  • DISTINCT 를 빼먹으면 중복 행이 그대로 남아 6행이 된다.
  • DISTINCT 가 첫 열에만 적용된다고 보면 수학A 가 한 행으로 줄어든다.
문제 13
다음 SQL에 대한 설명으로 옳은 것은? (개강일은 [강좌] 테이블의 열이다)
SELECT 강사번호, COUNT(*) AS 강좌수
  FROM 강좌
 GROUP BY 강사번호
 ORDER BY 개강일;
1SELECT 목록에 있는 열로만 정렬된다
2강사별 개강일 순으로 정렬되어 나온다
3그룹화 뒤라 개강일로는 정렬할 수 없다
4정렬이 WHERE 보다 먼저 실행된다
정답 및 해설

논리적 실행 순서가 FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY 이므로 그룹화 뒤의 ORDER BY 에서는 그룹 기준 열과 집계 결과만 쓸 수 있어 개강일 정렬은 오류가 난다.

그룹을 만들지 않은 일반 SELECT 라면 SELECT 목록에 없는 열로도 정렬할 수 있다.

  • GROUP BY 가 없을 때는 SELECT 목록 밖의 열로도 정렬된다.
  • 강사별로 개강일이 여러 개라 한 값으로 정렬할 수 없어 오류다.
  • ORDER BY 는 가장 마지막에 실행되며 WHERE 가 먼저다.
문제 14
다음 [강좌] 테이블에 대해 SQL을 실행한 결과로 옳은 것은? (Oracle 기준)

[강좌]

강좌명개강일종강일
회화A2026-01-152026-02-14
문법B2026-02-022026-03-01
작문C2026-03-102026-04-09
독해D2026-04-012026-04-30
SELECT 강좌명,
       종강일 - 개강일 AS 기간,
       TO_CHAR(LAST_DAY(개강일), 'DD') AS 말일
  FROM 강좌
 WHERE 개강일 >= TO_DATE('2026-02-01', 'YYYY-MM-DD')
 ORDER BY 개강일;
1
강좌명기간말일
문법B2828
작문C3131
독해D3030
2
강좌명기간말일
문법B2728
작문C3031
독해D2930
3
강좌명기간말일
회화A3031
문법B2728
작문C3031
독해D2930
4
강좌명기간말일
문법B2731
작문C3030
독해D2930
정답 및 해설

Oracle 에서 날짜−날짜는 두 날짜 사이의 일수(끝−시작)이고 LAST_DAY 는 그 달의 마지막 날을 돌려주며, WHERE 조건으로 2026-02-01 이후 개강한 세 강좌만 남는다.

문법B 는 2월 2일부터 3월 1일까지라 27, 2월 말일은 28 이고 작문C 는 30·31, 독해D 는 29·30 이 된다.

  • 시작일을 포함해 하루를 더하면 28·31·30 이 되지만 단순 차가 결과다.
  • 회화A 는 1월 15일 개강이라 WHERE 조건에서 빠진다.
  • LAST_DAY 는 종강일이 아니라 개강일 기준이라 문법B 의 말일은 28 이다.
문제 15
다음 SQL의 실행 결과로 옳은 것은?

[성적]

수강생명점수
가온95
나래70
다솜(null)
라희69
마루88
SELECT 수강생명,
       CASE WHEN 점수 >= 70 THEN 'B'
            WHEN 점수 >= 90 THEN 'A'
            WHEN 점수 < 70  THEN 'C'
       END AS 등급
  FROM 성적
 ORDER BY 수강생명;
1
수강생명등급
가온B
나래B
다솜C
라희C
마루B
2
수강생명등급
가온B
나래B
다솜(null)
라희C
마루B
3
수강생명등급
가온A
나래B
다솜(null)
라희C
마루B
4
수강생명등급
가온B
나래C
다솜(null)
라희C
마루B
정답 및 해설

검색형 CASE 는 WHEN 을 위에서부터 평가해 처음 참이 된 THEN 값만 돌려주므로 95점인 가온도 첫 조건(70 이상)에 걸려 B 가 된다.

점수가 NULL 인 다솜은 모든 비교가 UNKNOWN 이고 ELSE 가 없어 NULL 이며, 69점인 라희만 C 를 받는다.

  • 뒤의 90 이상 조건은 앞 조건에 먼저 걸려 한 번도 쓰이지 않는다.
  • NULL 은 70 미만 비교에서도 참이 아니라 C 가 되지 않는다.
  • 70점은 70 이상 조건을 만족하므로 나래는 B 를 받는다.
문제 16
다음 [강좌] 테이블에서 하이픈(-) 뒤의 번호만 꺼내 원하는 결과를 얻으려 한다. ( ㉠ )에 들어갈 식으로 옳은 것은? (Oracle 기준)

[강좌]

강좌코드강좌명
EN-101영어회화
MATH-202수학심화
SCI-35과학탐구
KR-7국어독해
SELECT 강좌코드,
       ( ㉠ ) AS 번호
  FROM 강좌
 ORDER BY 강좌코드;

[원하는 결과]

강좌코드번호
EN-101101
KR-77
MATH-202202
SCI-3535
1SUBSTR(강좌코드, INSTR(강좌코드, '-') + 1)
2REPLACE(강좌코드, '-', '')
3RTRIM(강좌코드, '0123456789')
4SUBSTR(강좌코드, -3)
정답 및 해설

INSTR 로 하이픈 위치를 찾고 그다음 칸부터 SUBSTR 로 끝까지 자르면 앞 글자 수와 번호 자릿수가 달라도 101·7·202·35 를 정확히 얻는다.

SUBSTR 의 길이 인수를 생략하면 시작 위치부터 문자열 끝까지 반환한다.

  • 뒤에서 3자를 자르면 SCI-35 는 -35, KR-7 은 R-7 이 된다.
  • REPLACE 는 하이픈만 지워 EN101 처럼 앞 글자가 남는다.
  • RTRIM 은 오른쪽 숫자를 지워 EN- 같은 앞부분만 남긴다.
문제 17
다음 SQL을 실행했을 때 결과 행의 수는?

[강좌]

강좌번호과목레벨수강료
1수학A90
2수학B120
3영어A80
4영어B130
5국어C100
6과학B90
7영어C150
SELECT 강좌번호, 과목
  FROM 강좌
 WHERE NOT 과목 = '수학' AND 수강료 >= 100 OR 레벨 = 'A'
 ORDER BY 강좌번호;
13
26
34
45
정답 및 해설

우선순위가 NOT > AND > OR 이므로 조건은 ((NOT 과목='수학') AND 수강료>=100) OR 레벨='A' 로 묶여 강좌 4·5·7 과 레벨 A 인 1·3 이 남아 5행이다.

NOT 은 바로 뒤 비교식 하나에만 적용되고, 수학 강좌라도 레벨이 A 면 OR 오른쪽 조건으로 통과한다.

  • NOT 을 뒤 조건 전체에 씌우면 4·5·6·7 의 4행이 된다.
  • OR 을 먼저 묶으면 수학 강좌 1 이 빠져 3·4·5·7 의 4행이 된다.
  • 레벨 A 조건까지 NOT 과 AND 로 묶였다고 보면 4·5·7 의 3행으로 줄어든다.
문제 18
[강좌] 테이블에서 WHERE 강좌명 LIKE '_어%' 조건을 만족하는 강좌명은?
1어휘특강
2중국어
3고급 영어
4영어회화
정답 및 해설

LIKE 에서 _ 는 정확히 한 글자, % 는 0개 이상의 글자를 뜻하므로 '_어%' 는 두 번째 글자가 '어'인 문자열이다.

영어회화는 첫 글자 '영' 뒤에 '어'가 오고 나머지 글자는 % 가 받아 조건을 만족한다.

  • 어휘특강은 '어'가 첫 글자라 앞의 _ 한 글자를 채우지 못한다.
  • 중국어는 두 번째 글자가 '국'이라 맞지 않는다.
  • 고급 영어는 두 번째 글자가 '급'이라 맞지 않는다.
문제 19
다음 SQL의 실행 결과로 옳은 것은?

[강좌]

강좌번호강사번호수강료
1T1120
2T180
3T1100
4T2150
5T290
6T3110
7T3130
8T3(null)
SELECT 강사번호, COUNT(*) AS 강좌수, SUM(수강료) AS 합계
  FROM 강좌
 WHERE 수강료 >= 100
 GROUP BY 강사번호
HAVING COUNT(*) >= 2
 ORDER BY 강사번호;
1
강사번호강좌수합계
T12220
T21150
T32240
2
강사번호강좌수합계
T13300
T22240
T33240
3
강사번호강좌수합계
T12220
T33240
4
강사번호강좌수합계
T12220
T32240
정답 및 해설

WHERE 가 그룹화 전에 수강료 100 이상 행만 남기므로 T1 은 120·100, T2 는 150, T3 는 110·130 만 집계되고(NULL 은 비교가 UNKNOWN 이라 제외) 이어서 HAVING 이 2건 이상인 그룹만 남긴다.

그래서 1건뿐인 T2 가 빠지고 T1(2건, 220)과 T3(2건, 240) 두 행이 나온다.

  • HAVING 을 무시하면 1건인 T2 까지 결과에 남는다.
  • 수강료가 NULL 인 행은 WHERE 에서 이미 빠져 T3 의 건수는 3 이 아니다.
  • WHERE 를 무시하고 전체 행을 세면 건수와 합계가 모두 커진다.
문제 20
다음 SQL을 실행했을 때 결과 행의 수는?

[수강생]

번호지점나이
1강남17
2강남25
3강남(null)
4분당19
5분당19
6분당(null)
7(null)30
8(null)15
SELECT CASE WHEN 나이 < 20 THEN '청소년' ELSE '성인' END AS 구분,
       지점, COUNT(*) AS 인원
  FROM 수강생
 GROUP BY CASE WHEN 나이 < 20 THEN '청소년' ELSE '성인' END, 지점
 ORDER BY 1, 2;
17
24
36
45
정답 및 해설

나이가 NULL 이면 '나이 < 20' 이 UNKNOWN 이라 ELSE 로 가서 성인이 되고, 지점이 NULL 인 행도 GROUP BY 에서 하나의 그룹을 이룬다.

강남·분당·지점 NULL 이 각각 청소년과 성인 두 그룹씩으로 묶여 6행이며, 분당의 19세 두 명은 한 그룹으로 합쳐진다.

  • 지점이 NULL 인 행을 버리면 강남·분당 네 그룹만 남아 4행이 된다.
  • 나이 NULL 행이 빠진다고 보면 분당 성인 그룹이 사라져 5행이 된다.
  • 나이 NULL 을 별도 구분으로 보면 강남·분당에 그룹이 생겨 7행으로 센다.
문제 21
다음 [강좌] 테이블 전체를 대상으로 SELECT 절에 넣어 실행했을 때 결과가 나머지 셋과 다른 것은?

[강좌]

강좌번호수강료
1100
2200
3(null)
4300
1SUM(수강료) / COUNT(수강료)
2MAX(수강료) - MIN(수강료)
3AVG(COALESCE(수강료, 0))
4AVG(수강료)
정답 및 해설

AVG·SUM·COUNT(열)은 NULL 행을 제외하고 계산하므로 AVG(수강료)는 600/3=200 이지만, COALESCE 로 NULL 을 0 으로 바꾸면 4행 모두 평균에 들어가 600/4=150 이 된다.

집계 전에 NULL 을 다른 값으로 바꾸면 분모가 달라진다는 점이 핵심이다.

  • AVG(수강료)는 NULL 을 빼고 세 값을 평균해 200 이다.
  • SUM 600 을 COUNT(수강료) 3 으로 나누어 200 이다.
  • MAX·MIN 도 NULL 을 빼고 300 과 100 으로 계산해 차가 200 이다.
문제 22
다음 SQL의 실행 결과로 옳은 것은?

[수강생]

번호이름레벨점수
1하늘중급80
2보람고급70
3구름초급95
4별빛고급90
5노을(null)85
6새벽중급80
SELECT 이름, 점수
  FROM 수강생
 ORDER BY CASE 레벨 WHEN '고급' THEN 1
                   WHEN '중급' THEN 2
                   ELSE 3 END,
          점수 DESC, 이름;
1
이름점수
별빛90
보람70
새벽80
하늘80
구름95
노을85
2
이름점수
구름95
별빛90
노을85
새벽80
하늘80
보람70
3
이름점수
별빛90
보람70
하늘80
새벽80
구름95
노을85
4
이름점수
보람70
별빛90
새벽80
하늘80
노을85
구름95
정답 및 해설

첫 정렬 키가 CASE 식이라 고급(1), 중급(2), 나머지(3) 순으로 묶이고, 레벨이 NULL 인 노을도 ELSE 로 3 이 되어 초급 구름과 함께 맨 뒤에 온다.

같은 묶음 안에서는 점수 DESC, 점수가 같은 새벽·하늘은 이름 오름차순으로 정렬되며 SELECT 목록에 없는 레벨도 정렬 키로 쓸 수 있다.

  • 점수를 오름차순으로 보면 보람이 별빛보다 앞서게 된다.
  • 동점에서 이름 오름차순이면 새벽이 하늘보다 먼저 온다.
  • CASE 키를 무시하고 점수만 보면 구름이 맨 앞에 오게 된다.
문제 23
다음 SQL을 실행했을 때 결과 행의 수는?

[수강생]

학번이름
S1민지
S2도윤
S3서연

[강좌]

강좌번호강좌명
C1영어
C2수학

[수강신청]

신청번호학번강좌번호
1S1C1
2S1C2
3S2C1
4S3C3
5(null)C2
6S2C2
SELECT S.이름, C.강좌명
  FROM 수강생 S, 수강신청 R, 강좌 C
 WHERE S.학번 = R.학번
   AND R.강좌번호 = C.강좌번호
 ORDER BY R.신청번호;
14
23
36
45
정답 및 해설

세 테이블을 조인하려면 N-1=2개의 조인 조건이 필요하고, 두 조건을 모두 만족하는 신청 1·2·3·6 만 남아 4행이다.

신청 4 는 강좌 C3 이 없어서, 신청 5 는 학번이 NULL 이라서 등가 조인에서 짝을 찾지 못해 빠진다.

  • 3행은 수강생 수로 센 것인데 한 수강생의 여러 신청은 각각 행이 된다.
  • 5행은 NULL 학번 신청까지 넣은 것이며 NULL 은 어떤 값과도 같지 않다.
  • 6행은 수강신청 전체 건수로 짝 없는 신청까지 센 것이다.
문제 24
다음 SQL의 실행 결과에 대한 설명으로 옳은 것은?

[강좌]

강좌번호강좌명선수강좌번호
C1기초영어(null)
C2중급영어C1
C3고급영어C2
C4기초수학(null)
C5토론영어C2
SELECT A.강좌명 AS 강좌, B.강좌명 AS 선수강좌
  FROM 강좌 A
  JOIN 강좌 B ON A.선수강좌번호 = B.강좌번호
 ORDER BY A.강좌번호;
1고급영어의 선수강좌는 기초영어로 나온다
2선수강좌가 있는 강좌만 3행 출력된다
3기초영어가 강좌 열에 한 번 나온다
4중급영어는 선수강좌 열에 한 번 나온다
정답 및 해설

A 는 강좌, B 는 선수강좌 역할을 하는 셀프 조인으로, 선수강좌번호가 NULL 인 기초영어·기초수학은 INNER JOIN 에서 짝이 없어 빠지고 3행만 나온다.

결과는 중급영어-기초영어, 고급영어-중급영어, 토론영어-중급영어이며 한 번의 조인은 바로 위 단계만 연결한다.

  • 기초영어는 선수강좌가 없어 강좌 열에는 나오지 않는다.
  • 중급영어는 고급영어와 토론영어의 선수강좌라 두 번 나온다.
  • 고급영어의 선수강좌는 바로 위 단계인 중급영어다.
문제 25
다음 SQL의 실행 결과로 옳은 것은?

[강사]

강사번호강사명지점코드
T1김하준B1
T2이서윤B2
T3박도현(null)
T4최지아B9

[지점]

지점코드지점명
B1강남
B2분당
B3일산
SELECT *
  FROM 강사 NATURAL JOIN 지점
 ORDER BY 강사번호;
1
지점코드강사번호강사명지점명
B1T1김하준강남
B2T2이서윤분당
(null)T3박도현(null)
B9T4최지아(null)
2
강사번호강사명지점코드지점명
T1김하준B1강남
T2이서윤B2분당
3
지점코드강사번호강사명지점명
B1T1김하준강남
B2T2이서윤분당
4
지점코드강사번호강사명지점코드지점명
B1T1김하준B1강남
B2T2이서윤B2분당
정답 및 해설

NATURAL JOIN 은 이름이 같은 지점코드로 등가 조인하고, SELECT * 에서 공통 열을 한 번만 맨 앞에 둔 뒤 강사와 지점의 나머지 열을 차례로 보여 준다.

지점코드가 NULL 인 T3 과 지점에 없는 B9 를 가진 T4 는 짝이 없어 빠지므로 결과는 2행이다.

  • NATURAL JOIN 은 내부 조인이라 짝 없는 T3·T4 를 NULL 로 남기지 않는다.
  • 공통 열은 왼쪽 테이블의 원래 위치가 아니라 결과 맨 앞에 온다.
  • 공통 열은 하나로 합쳐지므로 지점코드가 두 번 나오지 않는다.
문제 26
Oracle 기준으로 다음 ㉠의 결과 행 수와 ㉡의 결과 값을 순서대로 나열한 것은?

[강좌]

강좌번호강좌명
1국어
2수학
3영어

[수강신청]

학생번호강좌번호
1011
1021
1032
1044
105(null)

㉠

SELECT R.학생번호, C.강좌명
  FROM 강좌 C, 수강신청 R
 WHERE C.강좌번호(+) = R.강좌번호;

㉡

SELECT COUNT(*)
  FROM 강좌 C CROSS JOIN 수강신청 R
 WHERE C.강좌번호 <> R.강좌번호;
13, 12
25, 9
35, 12
44, 9
정답 및 해설

㉠은 (+) 가 강좌 쪽에 붙어 수강신청이 기준인 외부 조인(수강신청 LEFT OUTER JOIN 강좌)이므로 5행이고, ㉡은 CROSS JOIN 15행 중 같은 강좌 3쌍과 NULL 비교 3쌍을 뺀 9이다.

㉠에서 강좌번호가 4 인 신청과 강좌번호가 NULL 인 신청은 강좌명이 NULL 인 채 남고, 신청이 없는 영어는 나오지 않는다.

  • 4, 9 는 (+) 가 붙지 않은 강좌 쪽이 보존된다고 거꾸로 본 결과이다.
  • 5, 12 는 NULL 과의 <> 비교를 참으로 본 경우로, 결과는 UNKNOWN 이라 빠진다.
  • 3, 12 는 ㉠을 등가 조인으로 본 데다 NULL 비교까지 참으로 셈한 결과이다.
문제 27
다음 결과를 얻기 위해 ( ㉠ )에 들어갈 조인 구문으로 옳은 것은?

[강사]

강사번호이름
1윤서
2도현
3하린
4지안

[강좌]

강좌번호강좌명강사번호
10문학1
20미적분2
30회화1
40논술(null)
50물리5
SELECT T.이름, C.강좌명
  FROM 강사 T
  ( ㉠ ) 강좌 C
    ON T.강사번호 = C.강사번호
 WHERE T.강사번호 IS NULL
    OR C.강사번호 IS NULL
 ORDER BY T.이름, C.강좌명;
이름강좌명
지안(null)
하린(null)
(null)논술
(null)물리
1LEFT OUTER JOIN
2INNER JOIN
3RIGHT OUTER JOIN
4FULL OUTER JOIN
정답 및 해설

결과에 강좌가 없는 강사(하린·지안)와 강사가 연결되지 않은 강좌(논술·물리)가 함께 있으므로 양쪽 행을 모두 보존하는 FULL OUTER JOIN 이다.

조인 뒤 WHERE 의 IS NULL 조건은 짝을 찾은 문학·미적분·회화 행을 버리고, 한쪽 열이 NULL 로 채워진 행만 남긴다.

  • LEFT OUTER JOIN 은 강사 쪽만 보존해 하린·지안 2행만 남는다.
  • RIGHT OUTER JOIN 은 강좌 쪽만 보존해 논술·물리 2행만 남는다.
  • INNER JOIN 은 짝이 맞는 행만 만들어 WHERE 를 거치면 0행이다.
문제 28
다음 SQL 의 실행 결과로 옳은 것은?

[수강생]

학생번호이름
1민준
2서연
3지호
4하은

[수강신청]

학생번호강좌번호점수
11085
12092
210(null)
33070
310(null)
SELECT S.이름,
       (SELECT COUNT(*) FROM 수강신청 R
         WHERE R.학생번호 = S.학생번호) AS 신청수,
       (SELECT MAX(R.점수) FROM 수강신청 R
         WHERE R.학생번호 = S.학생번호) AS 최고점
  FROM 수강생 S
 ORDER BY S.학생번호;
1
이름신청수최고점
민준292
서연1(null)
지호270
하은0(null)
2
이름신청수최고점
민준292
서연1(null)
지호270
3
이름신청수최고점
민준292
서연1(null)
지호270
하은(null)(null)
4
이름신청수최고점
민준292
서연0(null)
지호170
하은0(null)
정답 및 해설

SELECT 절의 스칼라 서브쿼리는 수강생 한 행마다 한 값을 돌려주므로 4행이 모두 나오고, 신청이 없는 하은은 COUNT(*) 가 0, MAX 는 NULL 이다.

COUNT(*) 는 점수가 NULL 인 신청 행도 세므로 서연 1·지호 2 이고, MAX 는 NULL 을 빼고 계산해 서연은 NULL, 지호는 70 이다.

  • 하은의 신청수를 NULL 로 본 표는 대상 행이 없을 때 COUNT 도 NULL 이라고 오해한 것이다.
  • 하은이 빠진 표는 스칼라 서브쿼리를 내부 조인처럼 본 결과이다.
  • 서연 0·지호 1 인 표는 COUNT(*) 를 COUNT(점수)처럼 NULL 을 빼고 센 결과이다.
문제 29
신청 내역이 한 건도 없는 수강생을 다음 결과처럼 조회하려고 한다. ( ㉠ )에 들어갈 조건으로 옳은 것은?

[수강생]

학생번호이름
1민준
2서연
3지호
4하은
5도윤

[수강신청]

학생번호강좌번호점수
11080
220(null)
31075
(null)2090
SELECT S.이름
  FROM 수강생 S
 WHERE S.학생번호 NOT IN (SELECT R.학생번호
                            FROM 수강신청 R
                          ( ㉠ ))
 ORDER BY S.이름;
이름
도윤
하은
1WHERE R.강좌번호 = 10
2WHERE R.점수 >= 70
3WHERE R.학생번호 <> NULL
4WHERE R.학생번호 IS NOT NULL
정답 및 해설

서브쿼리 결과에 NULL 이 하나라도 있으면 NOT IN 은 모든 행에서 UNKNOWN 이 되어 0행이므로, 서브쿼리에서 IS NOT NULL 로 NULL 을 걸러야 하은·도윤이 나온다.

걸러진 서브쿼리 결과는 1·2·3 이고, 여기에 없는 학생번호 4·5 만 조건을 만족한다.

  • NULL 과의 <> 비교는 늘 UNKNOWN 이라 서브쿼리가 빈 집합이 되어 다섯 명이 모두 나온다.
  • 점수 70 이상 조건은 학생번호가 NULL 인 신청 행을 남겨 결과가 0행이 된다.
  • 강좌 10 조건은 1·3 만 돌려주어 서연까지 결과에 포함된다.
문제 30
다중행 서브쿼리 연산자에 대한 설명으로 옳은 것은?
1EXISTS 는 반환된 값을 서로 비교한다
2IN 서브쿼리는 한 행만 돌려줘야 한다
3= 연산자로 여러 행과 비교할 수 있다
4= ANY 는 IN 과 같은 결과를 낸다
정답 및 해설

= ANY 는 서브쿼리 결과 중 하나라도 같으면 참이므로 IN 과 같은 결과를 낸다.

다중행 서브쿼리에는 IN·ANY·ALL·EXISTS 같은 다중행 연산자를 쓰고, =·> 같은 단일행 연산자는 한 행만 돌려받아야 한다.

  • EXISTS 는 값을 비교하지 않고 서브쿼리 결과 행이 있는지만 확인한다.
  • 단일행 연산자 = 에 여러 행이 돌아오면 실행 오류가 난다.
  • IN 은 여러 행을 받는 다중행 연산자라 행 수 제한이 없다.
문제 31
다음 SQL 의 실행 결과로 옳은 것은?

[봄학기]

과목
국어
수학
수학

[여름학기]

과목
수학
영어

[특강]

과목
영어
과학
SELECT 과목 FROM 봄학기
UNION ALL
SELECT 과목 FROM 여름학기
UNION
SELECT 과목 FROM 특강
 ORDER BY 과목;
1
과목
국어
수학
영어
과학
2
과목
과학
국어
수학
수학
수학
영어
3
과목
과학
국어
수학
영어
4
과목
과학
국어
수학
수학
영어
정답 및 해설

집합 연산자는 왼쪽부터 차례로 계산되므로 봄학기와 여름학기를 UNION ALL 한 5행 전체가 마지막 UNION 의 입력이 되어 중복이 모두 제거된다.

남는 과목은 과학·국어·수학·영어 4개이고, 맨 끝 ORDER BY 가 전체 결과를 가나다순으로 정렬한다.

  • 수학 3행이 남은 표는 UNION 이 특강과 겹치는 영어만 제거한다고 본 결과이다.
  • 수학 2행이 남은 표는 봄학기 안의 중복은 UNION ALL 이라 보존된다고 본 결과이다.
  • 입력 순서대로 나온 표는 ORDER BY 가 마지막 SELECT 에만 적용된다고 오해한 것이다.
문제 32
Oracle 기준으로 다음 두 테이블의 집합 연산 결과에 대한 설명으로 옳은 것은?

[오전반]

과목
국어
수학
영어
영어

[오후반]

과목
수학
과학
1INTERSECT 결과는 수학과 영어이다
2MINUS 결과에는 중복 행이 남는다
3MINUS 는 두 테이블 순서와 무관하다
4오전반 MINUS 오후반 결과는 2행이다
정답 및 해설

오전반 MINUS 오후반은 오후반에 없는 국어·영어를 남기고 중복을 제거하므로 2행이다.

순서를 바꾼 오후반 MINUS 오전반은 과학 1행이며, 두 테이블의 INTERSECT 는 양쪽에 모두 있는 수학 1행이다.

  • MINUS 는 앞 집합에서 뒤 집합을 빼므로 순서를 바꾸면 결과가 달라진다.
  • 영어는 오후반에 없어 교집합에 들어가지 못한다.
  • MINUS 는 UNION 처럼 중복을 제거해 영어가 한 번만 나온다.
문제 33
다음 SQL 의 실행 결과로 옳은 것은?

[반편성]

과목반인원
수학A10
수학B8
영어A12
영어(null)5
SELECT 과목, 반, SUM(인원) AS 합계,
       GROUPING(반) AS G
  FROM 반편성
 GROUP BY GROUPING SETS ((과목, 반), 과목)
 ORDER BY 과목, G, 반;
1
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)51
영어(null)171
2
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)50
영어(null)171
3
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)171
4
과목반합계G
수학A100
수학B80
수학(null)181
영어A120
영어(null)50
영어(null)171
(null)(null)351
정답 및 해설

GROUPING SETS 에 적은 (과목, 반) 상세 4행과 과목 소계 2행만 만들어지며, 총계 행은 없다.

영어·NULL·5 는 원래 반이 NULL 인 상세 행이라 GROUPING(반)=0 이고, 소계 행의 NULL 만 집계로 생겨 1 이다.

  • 영어·NULL·5 의 G 를 1 로 본 표는 NULL 이면 모두 소계라고 오해한 것이다.
  • 영어·NULL·5 가 빠진 표는 NULL 반 상세 행을 소계와 합쳐 버린 결과이다.
  • 총계 35 행이 있는 표는 빈 그룹 () 을 적지 않았는데도 총계가 생긴다고 본 것이다.
문제 34
다음 SQL 의 실행 결과로 옳은 것은?

[시간표]

요일과목수강생수
월국어20
월수학15
화수학25
SELECT 요일, 과목, SUM(수강생수) AS 합계
  FROM 시간표
 GROUP BY ROLLUP (요일, 과목)
 ORDER BY 요일, 과목;
1
요일과목합계
월국어20
월수학15
화수학25
(null)국어20
(null)수학40
(null)(null)60
2
요일과목합계
월국어20
월수학15
월(null)35
화수학25
화(null)25
(null)(null)60
3
요일과목합계
월국어20
월수학15
월(null)35
화수학25
화(null)25
4
요일과목합계
월국어20
월수학15
월(null)35
화수학25
화(null)25
(null)국어20
(null)수학40
(null)(null)60
정답 및 해설

ROLLUP (요일, 과목) 은 (요일, 과목) 상세 → 요일별 소계 → 총계 순으로 집계하므로 상세 3행·소계 2행·총계 1행의 6행이다.

소계 행은 과목이 NULL 이고 ASC 정렬에서 NULL 이 뒤로 가므로 각 요일 상세 다음에, 총계 60 은 맨 끝에 온다.

  • 과목별 소계만 있는 표는 인수 순서를 바꾼 ROLLUP (과목, 요일) 의 결과이다.
  • 총계가 없는 표는 GROUP BY 요일, ROLLUP (과목) 처럼 부분 ROLLUP 일 때의 결과이다.
  • 요일·과목 소계를 모두 가진 표는 CUBE 의 결과이다.
문제 35
다음 결과를 얻기 위해 ( ㉠ )에 들어갈 구문으로 옳은 것은?

[강의매출]

강사과목매출
윤서국어30
윤서논술20
도현국어40
하린수학50
하린국어10
SELECT 강사, 과목, SUM(매출) AS 매출합
  FROM 강의매출
 GROUP BY ( ㉠ )
 ORDER BY 강사, GROUPING(과목), 과목;
강사과목매출합
도현국어40
도현(null)40
윤서국어30
윤서논술20
윤서(null)50
하린국어10
하린수학50
하린(null)60
1강사, ROLLUP (과목)
2ROLLUP (강사, 과목)
3CUBE (강사, 과목)
4GROUPING SETS (강사, 과목)
정답 및 해설

결과는 상세 5행과 강사별 소계 3행으로 8행이며 총계 행이 없으므로, 강사는 고정하고 과목만 ROLLUP 하는 부분 ROLLUP 인 강사, ROLLUP (과목) 이다.

부분 ROLLUP 은 괄호 밖 열을 모든 그룹에 붙이므로 강사가 NULL 인 총계 행이 생기지 않는다.

  • ROLLUP (강사, 과목) 은 끝에 총계 1행이 더해져 9행이 된다.
  • CUBE 는 과목별 소계와 총계까지 만들어 12행이 된다.
  • GROUPING SETS (강사, 과목) 은 상세 행 없이 강사별·과목별 집계 6행만 만든다.
문제 36
학생마다 결제일 순서로 금액을 누적한 다음 결과를 얻으려고 한다. ( ㉠ )에 들어갈 구문으로 옳은 것은?

[수강결제]

학생번호결제일금액
12026-03-02100
22026-03-03200
12026-03-05150
22026-03-0750
12026-03-09120
SELECT 학생번호, 결제일,
       SUM(금액) OVER (( ㉠ )) AS 누적액
  FROM 수강결제
 ORDER BY 학생번호, 결제일;
학생번호결제일누적액
12026-03-02100
12026-03-05250
12026-03-09370
22026-03-03200
22026-03-07250
1PARTITION BY 학생번호
2PARTITION BY 결제일
3ORDER BY 학생번호, 결제일
4PARTITION BY 학생번호 ORDER BY 결제일
정답 및 해설

학생번호가 바뀔 때마다 누적액이 처음부터 다시 쌓이고 결제일 순으로 늘어나므로 PARTITION BY 학생번호 와 ORDER BY 결제일 이 함께 있어야 한다.

학생 1 은 100·250·370, 학생 2 는 200·250 으로 파티션 안에서 현재 행까지 더한다.

  • ORDER BY 학생번호, 결제일 만 주면 파티션이 없어 학생 2 의 첫 값이 570 으로 이어진다.
  • PARTITION BY 학생번호 만 주면 누적이 아니라 학생별 합계 370·250 이 모든 행에 나온다.
  • PARTITION BY 결제일 은 날짜마다 파티션이 따로 생겨 각 행의 금액만 나온다.
문제 37
다음 SQL 의 실행 결과로 옳은 것은?

[모의평가]

학생회차점수
민준170
민준285
민준380
서연190
서연295
SELECT 학생, 회차,
       FIRST_VALUE(점수) OVER (PARTITION BY 학생 ORDER BY 회차
         ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS A,
       LAST_VALUE(점수) OVER (PARTITION BY 학생 ORDER BY 회차
         ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS B
  FROM 모의평가
 ORDER BY 학생, 회차;
1
학생회차AB
민준17085
민준27080
민준37080
서연19095
서연29095
2
학생회차AB
민준1(null)85
민준27080
민준38580
서연1(null)95
서연29095
3
학생회차AB
민준17085
민준27080
민준385(null)
서연19095
서연290(null)
4
학생회차AB
민준17085
민준27080
민준38580
서연19095
서연29095
정답 및 해설

A 는 직전 행~현재 행 프레임의 첫 값, B 는 현재 행~다음 행 프레임의 끝 값이므로 민준 3회차는 A=85·B=80 이 된다.

파티션 첫 행은 프레임에 자기 자신만 있어 A 가 자기 점수이고, 마지막 행도 B 가 자기 점수라서 NULL 이 생기지 않는다.

  • 첫 행 A 가 NULL 인 표는 FIRST_VALUE 를 LAG 처럼 본 결과이다.
  • 마지막 행 B 가 NULL 인 표는 LAST_VALUE 를 LEAD 처럼 본 결과이다.
  • 민준 3회차 A 가 70 인 표는 프레임을 무시하고 파티션 첫 값을 쓴 결과이다.
문제 38
Oracle 기준으로 다음 SQL 을 실행했을 때 수학 행의 R 과 C 값을 순서대로 나열한 것은?

[강좌현황]

강좌수강생수
국어20
수학30
영어40
과학10
SELECT 강좌,
       RATIO_TO_REPORT(수강생수) OVER () AS R,
       CUME_DIST() OVER (ORDER BY 수강생수) AS C
  FROM 강좌현황;
130, 0.75
20.75, 0.3
30.3, 0.75
40.3, 0.67
정답 및 해설

RATIO_TO_REPORT 는 전체 합 100 에 대한 비율이라 30/100=0.3 이고, CUME_DIST 는 수학 이하 값을 가진 3행을 전체 4행으로 나눠 0.75 이다.

CUME_DIST 는 현재 행을 포함한 누적 비율이라 마지막 행이 1 이 되며, (순위-1)/(행수-1) 로 계산하는 PERCENT_RANK 와 구별한다.

  • 0.67 은 PERCENT_RANK 공식 (3-1)/(4-1) 로 계산한 값이다.
  • 30 은 비율이 아니라 백분율로 착각한 값으로, 결과는 0~1 사이 소수이다.
  • 두 값의 순서를 서로 바꾼 조합이다.
문제 39
다음 SQL 의 결과 행 수와 전체 열의 값을 순서대로 나열한 것은?

[수강]

학생번호과목
1국어
2국어
3국어
4수학
5수학
6영어
7영어
8(null)
SELECT 과목, COUNT(*) AS 인원,
       SUM(COUNT(*)) OVER () AS 전체
  FROM 수강
 GROUP BY 과목;
13, 7
24, 8
38, 8
44, 4
정답 및 해설

윈도우 함수는 GROUP BY 가 끝난 뒤 그룹 행에 적용되므로 결과는 국어·수학·영어·NULL 의 4행이고, 각 그룹 인원 3·2·2·1 을 모두 더한 전체는 8 이다.

과목이 NULL 인 행도 하나의 그룹이 되며 COUNT(*) 는 그 행을 1 로 센다.

  • 8행은 윈도우 함수가 원본 행 수를 유지한다고 보고 GROUP BY 를 무시한 것이다.
  • 3행·7 은 NULL 그룹을 버린 결과로, GROUP BY 는 NULL 도 그룹으로 만든다.
  • 전체 4 는 SUM 이 그룹 개수를 센다고 본 값으로, 실제로는 인원을 더한다.
문제 40
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[성적]

이름점수
민준88
서연95
지호72
하은91
도윤88
유나60
SELECT 이름, 점수
  FROM (SELECT 이름, 점수
          FROM 성적
         ORDER BY 점수 DESC, 이름)
 WHERE ROWNUM <= 3
 ORDER BY 이름;
1
이름점수
도윤88
민준88
서연95
하은91
2
이름점수
서연95
하은91
도윤88
3
이름점수
도윤88
서연95
하은91
4
이름점수
도윤88
민준88
서연95
정답 및 해설

인라인 뷰가 점수 내림차순(동점은 이름순)으로 서연·하은·도윤·민준… 을 만든 뒤 ROWNUM <= 3 이 앞의 세 행을 자르고, 바깥 ORDER BY 이름 이 그 3행만 다시 정렬한다.

동점 88 인 도윤과 민준 중 이름순으로 앞선 도윤만 3위 안에 들어간다.

  • 도윤·민준·서연 표는 바깥 ORDER BY 가 ROWNUM 보다 먼저 적용된다고 본 결과이다.
  • 4행 표는 동점을 모두 포함하는 WITH TIES 처럼 본 것으로, ROWNUM 은 정확히 3행에서 멈춘다.
  • 점수순으로 나온 표는 바깥 ORDER BY 이름을 무시한 결과이다.
문제 41
Oracle(12c 이상)에서 다음 SQL 의 ( ㉠ ) 자리에 넣었을 때 오류가 발생하는 것은?
SELECT 이름, 점수
  FROM 성적
 ORDER BY 점수 DESC
( ㉠ );
1FETCH FIRST 50 PERCENT ROWS ONLY
2OFFSET 3 FETCH NEXT 3 ROWS ONLY
3FETCH NEXT 3 ROWS WITH TIES
4FETCH FIRST ROW ONLY
정답 및 해설

Oracle 의 행 제한절에서 OFFSET n 뒤에는 ROW 또는 ROWS 키워드가 반드시 와야 하므로 ROWS 가 빠진 구문은 오류이다.

FETCH 절도 건수 뒤에 ROW·ROWS 와 함께 ONLY 또는 WITH TIES 를 적어야 하며, 건수는 생략하면 1행으로 처리된다.

  • FETCH FIRST ROW ONLY 는 건수를 생략한 형태로 첫 1행을 돌려준다.
  • WITH TIES 는 ORDER BY 가 있으므로 3번째 점수와 같은 동점 행까지 포함한다.
  • PERCENT 는 전체 행 중 지정 비율만큼을 돌려주는 올바른 구문이다.
문제 42
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[강사]

강사번호이름멘토번호
1가온3
2나래1
3다솜2
4라온1
SELECT 이름, LEVEL AS LV,
       CONNECT_BY_ISCYCLE AS CYC
  FROM 강사
 START WITH 강사번호 = 1
CONNECT BY NOCYCLE PRIOR 강사번호 = 멘토번호
 ORDER SIBLINGS BY 이름;
1
이름LVCYC
가온11
나래20
다솜30
라온20
2
이름LVCYC
가온10
나래20
다솜31
라온20
3
이름LVCYC
가온10
나래20
다솜30
가온41
라온20
4
이름LVCYC
가온10
나래20
다솜30
라온20
정답 및 해설

가온의 멘토가 다솜이라 다솜 아래에 가온이 다시 이어지는 순환이 있지만, NOCYCLE 은 이미 지나온 가온을 다시 전개하지 않아 4행에서 멈춘다.

CONNECT_BY_ISCYCLE 은 자식이 자기 조상인 행에서 1 이므로, 자식 가온이 조상인 다솜만 1 이다.

  • 루트 가온에 1 을 준 표는 순환 대상 행 자체에 표시된다고 오해한 것이다.
  • 가온이 LEVEL 4 로 한 번 더 나온 표는 반복 행을 한 번 출력한 뒤 멈춘다고 본 결과이다.
  • 모두 0 인 표는 NOCYCLE 로 전개가 끊기면 순환 표시도 없다고 본 것이다.
문제 43
다음 SQL 에 대한 설명으로 옳은 것은?

[강사]

강사번호이름멘토번호
1가온(null)
2나래1
3다솜1
4라온2
SELECT A.이름 AS 강사, B.이름 AS 멘토
  FROM 강사 A
  LEFT OUTER JOIN 강사 B
    ON A.멘토번호 = B.강사번호;
1결과 행 수는 강사 수 4와 같다
2멘토가 없는 가온은 결과에서 빠진다
3멘토 열에는 부하의 이름이 나온다
4별칭을 빼도 같은 결과가 나온다
정답 및 해설

셀프 조인을 LEFT OUTER JOIN 으로 했으므로 A 쪽 강사 4명이 모두 남고, 각 강사의 멘토는 많아야 한 명이라 결과는 강사 수와 같은 4행이다.

가온은 멘토번호가 NULL 이라 짝이 없지만 멘토 열이 NULL 인 채로 결과에 나온다.

  • INNER JOIN 이었다면 가온이 빠지지만 외부 조인이라 보존된다.
  • B 는 A 의 멘토번호와 강사번호가 같은 행이므로 멘토(상위자)의 이름이다.
  • 같은 테이블을 두 번 쓰므로 별칭이 없으면 열을 구분할 수 없어 오류가 난다.
문제 44
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[출석]

반강사요일인원
A윤서월10
A윤서화12
A도현월8
B하린월15
B하린화5
SELECT *
  FROM 출석
 PIVOT (SUM(인원) FOR 요일 IN ('월' AS 월, '화' AS 화))
 ORDER BY 반, 강사;
1
반월화
A1812
B155
2
반강사월화
A도현8(null)
A윤서10(null)
A윤서(null)12
B하린15(null)
B하린(null)5
3
반강사월화
A도현8(null)
A윤서1012
B하린155
4
반강사월화
A도현80
A윤서1012
B하린155
정답 및 해설

PIVOT 은 집계 열(인원)과 FOR 열(요일)을 뺀 나머지 열 반·강사를 모두 그룹 기준으로 삼으므로 (A, 도현)·(A, 윤서)·(B, 하린)의 3행이 된다.

도현은 화요일 데이터가 없어 화 열이 0 이 아닌 NULL 이며, 같은 그룹의 월·화 값은 한 행으로 합쳐진다.

  • 반별 2행 표는 강사 열도 그룹 기준이 된다는 점을 놓친 결과로, 인라인 뷰로 강사를 빼야 나온다.
  • 도현의 화를 0 으로 본 표는 값이 없는 칸이 NULL 이라는 점을 놓친 것이다.
  • 원본 5행이 그대로 남은 표는 PIVOT 이 그룹별로 행을 합친다는 점을 무시한 결과이다.
문제 45
Oracle 기준으로 다음 SQL 의 실행 결과로 옳은 것은?

[강좌코드]

번호코드
1MATH-101
2MATH101
3ENG-20
4KOR-1001
5SCI--10
6math-102
SELECT 번호, 코드
  FROM 강좌코드
 WHERE REGEXP_LIKE(코드, '^[A-Z]{3,4}-?[0-9]{2,3}$')
 ORDER BY 번호;
1
번호코드
1MATH-101
2MATH101
3ENG-20
2
번호코드
1MATH-101
3ENG-20
3
번호코드
1MATH-101
2MATH101
3ENG-20
4KOR-1001
4
번호코드
1MATH-101
2MATH101
3ENG-20
6math-102
정답 및 해설

패턴은 대문자 3~4개, 하이픈 0~1개(?), 숫자 2~3개({2,3}) 로 문자열 전체가 이루어져야 하므로 번호 1~3 의 행만 일치한다.

KOR-1001 은 숫자가 4개라 $ 앞에서 어긋나고, SCI--10 은 하이픈이 2개, math-102 는 소문자라 [A-Z] 에 맞지 않는다.

  • KOR-1001 을 넣은 표는 {2,3} 을 2회 이상으로 보거나 $ 앵커를 무시한 결과이다.
  • MATH101 을 뺀 표는 ? 를 정확히 1회로 오해한 결과이다.
  • math-102 를 넣은 표는 기본 매칭이 대소문자를 구분한다는 점을 놓친 것이다.
문제 46
수료자 테이블에 유나 1행이 들어 있는 상태에서 다음 INSERT 문을 실행했을 때, 수료자 테이블의 전체 행 수는?

[수강생]

학생번호이름출석률
1민준95
2서연80
3지호(null)
4하은79
5도윤88
INSERT INTO 수료자 (학생번호, 이름)
SELECT 학생번호, 이름
  FROM 수강생
 WHERE 출석률 >= 80;
15
26
34
43
정답 및 해설

INSERT … SELECT 는 서브쿼리가 돌려준 행을 모두 한 번에 넣으므로 출석률 80 이상인 민준·서연·도윤 3행이 추가되어 기존 1행과 합쳐 4행이다.

80 은 >= 조건에 포함되고, 출석률이 NULL 인 지호는 비교 결과가 UNKNOWN 이라 들어가지 않는다.

  • 3 은 기존 유나 행이 지워지고 새로 채워진다고 본 값이다.
  • 5 는 출석률이 NULL 인 지호까지 넣은 값이다.
  • 6 은 WHERE 조건을 무시하고 수강생 전원을 넣은 값이다.
문제 47
Oracle 에서 수강생 테이블에 INSERT 를 하고 COMMIT 을 하지 않은 상태다. 이어서 일어난 일 중 그 INSERT 가 자동으로 확정되지 않는 경우는?
1CREATE TABLE 문을 실행했다
2GRANT 문을 실행했다
3SQL*Plus 를 EXIT 로 끝냈다
4정전으로 세션이 끊겼다
정답 및 해설

정전·장애로 세션이 비정상 종료되면 Oracle 은 커밋되지 않은 변경을 자동으로 ROLLBACK 하므로 INSERT 는 사라진다.

반대로 DDL·DCL 문은 실행 전후에 암시적 COMMIT 이 일어나고, 도구를 정상 종료할 때도 기본 설정에서 COMMIT 된다.

  • CREATE TABLE 은 DDL 이라 앞선 INSERT 가 함께 확정된다.
  • GRANT 는 DCL 이라 실행 시 앞선 INSERT 가 확정된다.
  • SQL*Plus 의 EXIT 정상 종료는 기본적으로 COMMIT 후 끝낸다.
문제 48
다음과 같이 정의된 테이블에서 강좌 10 에 대한 수강신청이 있고, 그 신청에 대한 출석 기록도 있다. DELETE 문 실행 결과에 대한 설명으로 옳은 것은?
CREATE TABLE 수강신청 (
  신청번호 INT PRIMARY KEY,
  강좌번호 INT REFERENCES 강좌(강좌번호)
           ON DELETE CASCADE
);
CREATE TABLE 출석 (
  출석번호 INT PRIMARY KEY,
  신청번호 INT REFERENCES 수강신청(신청번호)
);

DELETE FROM 강좌 WHERE 강좌번호 = 10;
1강좌만 삭제되고 수강신청은 남는다
2출석 기록까지 모두 연쇄 삭제된다
3오류가 나 어떤 행도 삭제되지 않는다
4강좌와 수강신청만 함께 삭제된다
정답 및 해설

강좌 삭제는 ON DELETE CASCADE 로 수강신청 삭제를 부르지만, 그 신청을 출석이 삭제 옵션 없는 기본 FK(제한)로 참조하고 있어 무결성 오류가 난다.

DELETE 문은 한 문장 단위로 처리되므로 연쇄 경로 어디에서든 오류가 나면 강좌·수강신청 모두 삭제되지 않는다.

  • CASCADE 가 지정돼 있어 강좌만 지우고 자식을 남기는 경우는 없다.
  • 수강신청까지 지우면 출석이 사라진 신청을 가리키게 되어 허용되지 않는다.
  • 출석 FK 에는 CASCADE 가 없으므로 출석까지 연쇄 삭제되지 않는다.
문제 49
Oracle 에서 CREATE TABLE 강좌 ( … ) 의 괄호 안에 넣었을 때 오류가 발생하는 열 정의는?
1개강일 DATE DEFAULT SYSDATE
2정원 NUMBER DEFAULT 0
3등급 CHAR DEFAULT 'A'
4강좌명 VARCHAR2 NOT NULL
정답 및 해설

Oracle 의 VARCHAR2 는 가변 길이 문자형이라 최대 길이를 VARCHAR2(30) 처럼 반드시 지정해야 하므로 길이가 빠진 정의는 오류이다.

반면 CHAR 는 길이를 생략하면 1, NUMBER 는 정밀도를 생략하면 최대 정밀도로 정의되어 실행된다.

  • 정원 정의는 정밀도 없는 NUMBER 에 기본값 0 을 준 올바른 구문이다.
  • 등급 정의는 길이 1 인 CHAR 에 한 글자 기본값을 준 올바른 구문이다.
  • 개강일 정의는 DATE 에 현재 일시 SYSDATE 를 기본값으로 준 올바른 구문이다.
문제 50
Oracle 에서 DBA 가 다음을 순서대로 실행했다(㉡·㉣은 강사A 가 실행). 실행 후 상태에 대한 설명으로 옳은 것은?
㉠ GRANT CREATE TABLE TO 강사A WITH ADMIN OPTION;
㉡ GRANT CREATE TABLE TO 조교B;
㉢ GRANT SELECT ON 성적 TO 강사A WITH GRANT OPTION;
㉣ GRANT SELECT ON 성적 TO 조교B;
㉤ REVOKE CREATE TABLE FROM 강사A;
㉥ REVOKE SELECT ON 성적 FROM 강사A;
1조교B 의 CREATE TABLE 은 남는다
2시스템 권한도 GRANT OPTION 을 쓴다
3조교B 는 성적을 계속 조회한다
4강사A 는 테이블을 계속 만든다
정답 및 해설

WITH ADMIN OPTION 으로 받은 시스템 권한은 강사A 에게서 회수해도 강사A 가 조교B 에게 준 권한이 연쇄 회수되지 않으므로 조교B 의 CREATE TABLE 은 남는다.

반면 WITH GRANT OPTION 으로 받은 객체 권한 SELECT 는 회수 시 강사A 가 넘겨준 조교B 의 권한까지 함께 회수된다.

  • 객체 권한 회수는 연쇄되므로 조교B 도 성적을 조회할 수 없다.
  • 시스템 권한의 재부여 옵션은 WITH ADMIN OPTION 이고 GRANT OPTION 은 객체 권한용이다.
  • 강사A 는 CREATE TABLE 이 회수되어 더 이상 테이블을 만들 수 없다.