이상 현상(anomaly)은 한 표에 여러 주제를 담아 같은 값이 되풀이될 때, 행을 넣거나 지우거나 고치면서 생기는 문제입니다. 삽입 이상·삭제 이상·갱신 이상 세 가지가 있습니다.
SQLD를 먼저 공부했다면 이 단원 끝의 모의 문제부터 풀어 보고, 틀린 문제가 나온 레슨만 골라 봐도 됩니다.
수강 신청 한 건마다 학번·이름·학과명·과목코드·점수를 한 줄에 적는 표를 생각해 봅시다. 표 하나만 보면 되니 처음에는 편해 보입니다. 하지만 한 학생이 과목을 셋 들으면 그 학생의 이름과 학과명이 세 줄에 적힙니다. 같은 값이 여러 곳에 되풀이되는 것을 중복(redundancy)이라 합니다. 중복이 있는 표는 행을 넣고, 지우고, 고칠 때마다 뜻하지 않은 문제를 일으킵니다.
이 레슨은 행을 다루는 SQL 문 셋으로 이상 현상을 직접 일으켜 봅니다. INSERT는 표에 행을 넣고, DELETE는 조건에 맞는 행을 지우고, UPDATE는 조건에 맞는 행의 값을 고칩니다. 문장의 꼴은 13단원에서 자세히 배웁니다. 더 보기: DML: INSERT·UPDATE·DELETE
그림의 수강신청 표는 수강 기록 12행에 학생 이름과 학과명을 붙인 표입니다. 한 행은 학번과 과목코드를 함께 봐야 구별되므로 기본키는 '학번 + 과목코드'입니다. 학생·학과·수강 세 가지 사실이 한 줄에 섞여 있어서 김민수는 3번, '컴퓨터'는 7번 적혀 있습니다. 아래 네 절은 이 한 표에서 차례로 일어나는 일 셋과, 그 셋을 한꺼번에 만드는 원인입니다.
1삽입 이상 — 신청하지 않은 학생을 넣지 못한다
삽입 이상(insertion anomaly)은 넣고 싶은 정보만으로는 행을 넣을 수 없는 문제입니다. 정하윤(106)은 아직 수강 신청을 하지 않았습니다. 이 표에 넣으려면 과목코드를 비워야 하는데, 과목코드는 기본키의 일부라 비울 수 없습니다. 넣으려면 듣지도 않는 과목을 꾸며 함께 넣어야 합니다. 학생이 없는 경영 학과(BA)도 이 표에는 적을 자리가 없습니다.
2삭제 이상 — 수강을 지우자 학생까지 사라진다
삭제 이상(deletion anomaly)은 행을 지울 때 남겨야 할 정보까지 함께 사라지는 문제입니다. 강도현(107)은 네트워크(NW) 한 과목만 들었습니다. 수강을 취소해 그 행을 지우면 강도현이라는 학생이 있다는 사실까지 표에서 사라집니다.
3갱신 이상 — 한 줄만 고쳐 학과명이 둘이 된다
갱신 이상(update anomaly)은 같은 값이 적힌 행 가운데 일부만 고쳐 값이 서로 어긋나는 문제입니다. 컴퓨터 학과의 이름이 '컴퓨터공학'으로 바뀌면 '컴퓨터'가 적힌 7행을 모두 고쳐야 합니다. 한 행만 고치면 같은 학과의 이름이 둘이 됩니다.
4원인은 중복, 해법은 정규화
세 이상 현상은 모두 한 표에 여러 주제를 담아 같은 값이 되풀이되기 때문에 생깁니다. 학생·학과·수강을 각각 다른 표에 두면 이름과 학과명을 한 번씩만 적게 됩니다. 이렇게 주제마다 표를 나누는 일을 정규화(normalization)라 합니다. 어디를 기준으로 나누는지는 다음 레슨 함수 종속부터 봅니다.
예제
본문 세 절에서 말한 일이 정말 일어나는지 수강신청 표에 직접 넣고 지우고 고쳐 봅니다. 수강신청 표는 예제 데이터의 수강·학생·학과 세 표를 이어 만든 다섯 열 12행 표이고, 기본키는 '학번 + 과목코드'입니다. 표를 만들고 잇는 문법(CREATE TABLE·조인)은 13·14단원에서 배우니, 여기서는 어떤 일이 막히고 무엇이 남는지만 보면 됩니다.
SQL로 확인하기
네 블록은 모두 같은 두 문장으로 시작합니다. CREATE TABLE … AS SELECT가 세 표를 이어 수강신청 표를 만들고, ALTER TABLE이 '학번 + 과목코드'를 기본키로 정합니다. 블록 하나만 복사해 돌려도 되도록 블록마다 표를 새로 만듭니다.
CREATE TABLE 수강신청 AS
SELECT E.학번,
S.이름,
D.학과명,
E.과목코드,
E.점수
FROM 수강 E
JOIN 학생 S
ON S.학번 = E.학번
LEFT JOIN 학과 D
ON D.학과코드
= S.학과코드;
ALTER TABLE 수강신청
ADD PRIMARY KEY
(학번, 과목코드);
SELECT *
FROM 수강신청
ORDER BY 학번, 과목코드;| 학번 | 이름 | 학과명 | 과목코드 | 점수 |
|---|---|---|---|---|
| 101 | 김민수 | 컴퓨터 | DS | 85 |
| 101 | 김민수 | 컴퓨터 | NW | 80 |
| 101 | 김민수 | 컴퓨터 | OS | 75 |
| 102 | 이서준 | 컴퓨터 | DS | 70 |
| 102 | 이서준 | 컴퓨터 | OS | 60 |
| 103 | 김지민 | 컴퓨터 | DS | 65 |
| 103 | 김지민 | 컴퓨터 | NW | 55 |
| 104 | 박서연 | 전자 | NW | 95 |
| 104 | 박서연 | 전자 | OS | 75 |
| 105 | 최민준 | 전자 | DS | 100 |
| 105 | 최민준 | 전자 | NW | 90 |
| 107 | 강도현 | NULL | NW | 50 |
강도현(107)은 아직 학과가 정해지지 않아 학과명이 NULL입니다. 수강하지 않은 정하윤(106)과 학생이 없는 경영 학과는 표에 없습니다.
삽입 이상 — 수강하지 않은 학생 넣기
정하윤(106)을 과목 없이 넣으려고 학번·이름·학과명만 적으면, 적지 않은 과목코드가 NULL이 되어 막힙니다. 기본키 열에는 NULL을 넣을 수 없다는 오류(ORA-01400)입니다.
SQL로 확인하기
CREATE TABLE 수강신청 AS
SELECT E.학번,
S.이름,
D.학과명,
E.과목코드,
E.점수
FROM 수강 E
JOIN 학생 S
ON S.학번 = E.학번
LEFT JOIN 학과 D
ON D.학과코드
= S.학과코드;
ALTER TABLE 수강신청
ADD PRIMARY KEY
(학번, 과목코드);
INSERT INTO 수강신청
(학번, 이름, 학과명)
VALUES (106, '정하윤',
'전자');삭제 이상 — 하나뿐인 수강 행 지우기
강도현(107)의 수강 행을 지운 뒤 이름이 강도현인 행을 세면 0행입니다. 지운 것은 수강 기록 하나인데, 강도현이라는 학생이 있다는 사실까지 이 표에서 사라졌습니다.
SQL로 확인하기
COUNT(*)는 행의 수를 셉니다.
CREATE TABLE 수강신청 AS
SELECT E.학번,
S.이름,
D.학과명,
E.과목코드,
E.점수
FROM 수강 E
JOIN 학생 S
ON S.학번 = E.학번
LEFT JOIN 학과 D
ON D.학과코드
= S.학과코드;
ALTER TABLE 수강신청
ADD PRIMARY KEY
(학번, 과목코드);
DELETE FROM 수강신청
WHERE 학번 = 107;
SELECT COUNT(*) AS 행수
FROM 수강신청
WHERE 이름 = '강도현';| 행수 |
|---|
| 0 |
갱신 이상 — 한 행만 고치기
학과 이름이 '컴퓨터공학'으로 바뀌었는데 김민수의 자료구조(DS) 행 하나만 고치면, 같은 김민수의 세 행에 학과명이 '컴퓨터공학'과 '컴퓨터' 둘로 남습니다.
SQL로 확인하기
CREATE TABLE 수강신청 AS
SELECT E.학번,
S.이름,
D.학과명,
E.과목코드,
E.점수
FROM 수강 E
JOIN 학생 S
ON S.학번 = E.학번
LEFT JOIN 학과 D
ON D.학과코드
= S.학과코드;
ALTER TABLE 수강신청
ADD PRIMARY KEY
(학번, 과목코드);
UPDATE 수강신청
SET 학과명 = '컴퓨터공학'
WHERE 학번 = 101
AND 과목코드 = 'DS';
SELECT 학번,
과목코드,
학과명
FROM 수강신청
WHERE 학번 = 101
ORDER BY 과목코드;| 학번 | 과목코드 | 학과명 |
|---|---|---|
| 101 | DS | 컴퓨터공학 |
| 101 | NW | 컴퓨터 |
| 101 | OS | 컴퓨터 |
같은 김민수의 행인데 학과명이 둘입니다.
어긋나지 않게 고치려면 WHERE 학과명 = '컴퓨터'로 7행을 한꺼번에 고쳐야 합니다.
같은 사실을 일곱 곳에 적어 두는 한, 고칠 때마다 일곱 곳을 모두 찾아야 합니다.
시험 포인트
- 필기: 이상 현상은 삽입·삭제·갱신 세 가지입니다. 넣고 싶은 정보만으로는 넣을 수 없으면 삽입 이상, 지울 때 다른 정보까지 사라지면 삭제 이상, 일부 행만 고쳐 값이 어긋나면 갱신 이상입니다. 원인은 한 표에 여러 주제를 담아 생긴 중복이고, 없애는 방법은 정규화입니다. 사례를 보고 이름을 고르는 문제로 나옵니다.
- 실기: 삽입 이상(Insertion Anomaly)·삭제 이상(Deletion Anomaly)·갱신 이상(Update Anomaly).
확인 문제
1. 학생명부 표(학번, 이름, 학년, 학과명, 건물)는 학생 표와 학과 표를 한 표로 합친 것입니다. 기본키는 학번이고, 전자 학과 학생은 박서연·최민준·정하윤 세 행입니다. 다음 가운데 갱신 이상이 생기는 것을 고르세요.
- ① 학생이 아직 한 명도 없는 경영 학과를 이 표에 적으려 하니 학번 자리를 비울 수 없어 막힌다
- ② 정하윤의 학년을 3에서 4로 고친다
- ③ 전자 학과가 새 건물로 옮겨 세 행 가운데 박서연의 행만 건물을 고친다
- ④ 전자 학과 학생 셋이 모두 졸업해 세 행을 지우니 전자 학과가 공학관에 있다는 사실도 표에서 사라진다
정답
③입니다. 건물은 학과에 딸린 사실인데 이 표에는 학생마다 적혀 있습니다. 전자 학과 세 행 가운데 하나만 고치면 같은 학과의 건물이 둘이 되어 값이 어긋납니다.
- ① 이상 현상 셋의 이름을 바꿔 봤습니다. 넣고 싶은 정보만으로 행을 넣을 수 없는 것은 삽입 이상입니다.
- ② 고치는 일이면 모두 갱신 이상이라고 봤습니다. 학년은 정하윤 한 사람에게만 딸린 사실이라 한 행에만 적혀 있어 어긋날 곳이 없습니다.
- ④ 사라지는 일도 값이 달라지는 것으로 봤습니다. 지울 때 남겨야 할 사실까지 사라지면 삭제 이상입니다.
2. 도서관이 대출 표(회원번호, 회원이름, 책번호, 제목, 대출일) 하나에 대출 기록을 적습니다. 기본키는 '회원번호 + 책번호'입니다. 다음 (가)~(다)에 맞는 이름을 한글 이름과 영문으로 함께 쓰세요. 답을 끝까지 쓴 뒤 정답을 펼치세요.
- (가) 새로 들어온 책을 목록에 올리려는데 아직 빌린 회원이 없어 회원번호 자리를 비워야 해서 올리지 못합니다.
- (나) 이름이 바뀐 회원의 대출 행 여러 개 가운데 하나만 손대, 같은 회원의 이름이 행마다 다릅니다.
- (다) 한 회원만 빌렸던 책의 대출 기록을 치우니 그 책의 제목까지 표에서 찾을 수 없습니다.
정답
받는 답: (가) 삽입 이상(Insertion Anomaly) · (나) 갱신 이상(Update Anomaly) · (다) 삭제 이상(Deletion Anomaly)
(가)의 실마리는 '기본키의 일부가 비어 행을 올릴 수 없다', (나)는 '같은 사실이 적힌 행 가운데 일부만 달라졌다', (다)는 '치운 기록과 함께 남겨야 할 사실까지 없어졌다'입니다. (가)와 (다)는 둘 다 책 정보를 잃는 이야기라 헷갈립니다. 올릴 때 막히면 (가), 치울 때 함께 사라지면 (다)입니다.
- 같은 이름의 다른 꼴: Insertion Anomaly처럼 영문만 쓴 꼴 — 문제가 한글 이름과 영문을 함께 쓰라고 했습니다.
- 같은 이름의 다른 꼴: '삽입'·'갱신'·'삭제'만 쓴 꼴 — 뒤의 '이상'까지 붙인 이름이 답입니다.
- 틀리는 꼴 삽입 이상 — (다)에: 넣고 싶은 정보만으로는 행을 넣을 수 없는 문제입니다. (다)는 이미 있던 행을 치우면서 사실을 잃었습니다.
- 틀리는 꼴 갱신 이상 — (가)에: 같은 값이 적힌 행 가운데 일부만 고쳐 값이 어긋나는 문제입니다. (가)는 행을 올리지도 못했습니다.
3. 예제의 DELETE 조건을 과목코드 = 'DS'로 바꿔 자료구조 행을 모두 지웠습니다. 몇 행이 지워지고, 표에서 사라지는 사실은 무엇일까요?
SQL로 확인하기
CREATE TABLE 수강신청 AS
SELECT E.학번,
S.이름,
D.학과명,
E.과목코드,
E.점수
FROM 수강 E
JOIN 학생 S
ON S.학번 = E.학번
LEFT JOIN 학과 D
ON D.학과코드
= S.학과코드;
ALTER TABLE 수강신청
ADD PRIMARY KEY
(학번, 과목코드);
DELETE FROM 수강신청
WHERE 과목코드 = 'DS';
SELECT DISTINCT 과목코드
FROM 수강신청
ORDER BY 과목코드;정답
4행이 지워지고, 남은 과목코드는 둘입니다.
| 과목코드 |
|---|
| NW |
| OS |
자료구조를 들은 101·102·103·105는 모두 다른 과목 행이 남아 학번·이름·학과명이 그대로 있습니다. 사라진 것은 'DS라는 과목이 있다'는 사실입니다. 삭제 이상은 학생 쪽에만 생기는 것이 아닙니다. 한 표에 함께 담은 주제라면 어느 쪽에든 생깁니다.
더 자세히: SQLD의 정규화 레슨은 사원·부서·프로젝트 표로 같은 이상 현상과 정규화를 한 번에 봅니다.