데이터베이스 시스템이 관리하고자 하는 데이터베이스는 단순히 데이터의 모임이 아니고, 특정 조건을 만족하는 데이터베이스이어야 한다. 특정 조건을 만족하는 데이터베이스이어야 사용자에게 의미가 있다. 예를 들어 사람의 나이 속성 값이 음수이면 그 데이터는 정확하지 않은 데이터이며(not accuracy), 사람의 나이가 한 테이블에서는 20이고 동일 사람 나이가 다른 테이블에서는 25이면 데이터가 서로 일치하지(consistency) 않아 잘못된 데이터이다.
name varchar(20) not null
not null
이 됨null
을 가질 수 있음Create table teaches (
pID char(5),
cID char(5),
semester varchar(10),
year numeric(4,0),
classroom char(5),
primary key (pID, cID, semester, year),
check (semester in (’Spring’, ‘Summer’, ’Fall’, ’Winter’) )
);
다만 외래 키는 널 값을 가질 수 있으나, 외래 키가 참조하는 주키는 해당 테이블의 주키이므로 널 값이 나올 수 없다.
참조 무결성 제약은 서로다른 두 관계 사이에 존재하며, 동일 관계 내에서도 존재할 수 있다. 참조 무결성 제약은 연관되는 데이터(터플) 연결을 값(value)를 이용하여 하기 때문에 발생하는 현상이다. 만약 터플간의 관계를 값이 아닌 포인터로 연결을 하는 경우에는 참조 무결성이 존재하지 않는다.
참조 무결성을 구체적인 행동(action) 명시 없이 선언할 수 있으며,
이 경우 참조 무결성이 위반되는 경우는 허용하지 않는다.
Create table teaches (
pID varchar(5),
cID varchar(5),
…
primary key(pID, cID, semester, year),
foreign key(pID) references professor,
foreign key(cID) references course
);
참조 무결성을 선언함에 있어 참조 무결성이 위반되는 경우가 존재한다면,
이를 해결하는 구체적인 행동까지 명시할 수 있다. 사용자가 명시할 수 있는 행동은 cascade
, set null
, set default
이다.
Create table teaches (
pID varchar(5),
cID varchar(5),
…
foreign key(pID) references professor,
on delete cascade,
on update cascade,
…
);
참조 무결성은 외래키를 가지는 테이블에서 선언됨을 알 수 있고, 참조되는 테이블에서는 선언 하는 부분이 없다.
또한 외래키를 선언하면서 함께 명시하는 행동 부분에서 언급하는 delete/update 연산은 참조되는 테이블에 대한 삭제 및 갱신 연산을 의미한다.
on delete cascade
,on delete set null
,on delete set default
와 같이 쓸 수 있다.
I. on delete 연산
상기 예제에서 teacher의 pID는 professor 주 키 pID를 참조하는 외래 키이다.
professor 테이블의 <100, Kim, ...> 터플이 삭제되면, teaches 테이블에서 참조하는 터플로 인하여 참조 무결성이 위배된다.
이 경우, 행동이 명시되지 않았으면 (on delete
다음에 아무것도 없으면) 아예 삭제 연산이 허용되지 않으며,
cascade인 경우에는 삭제 연산이 teaches 테이블에 파급되어 삭제된 터플을 참조하는 두 터플이 모두 삭제된다.
<100, CS101,...>
과 <100, CS201, ...>
이 삭제 )set null 은 해당 테이블 속성 값을 널 값으로 한다. 즉, on delete set null
을 적어주었고, pID가 100인 교수가 삭제될 경우 <null, CS101>
, <null, CS201>
이 된다.
(pID, cID, semester, year)
이었다.그러나, 참조하는 테이블, teaches의 터플을 삭제하는 것은 참조 무결성 제약을 위배할 가능성이 전혀 없으므로 해당 터플만 삭제된다.
II. on update 연산
상기 예제에서 teacher의 pID는 professor 주 키 pID를 참조하는 외래 키이다.
professor 테이블의 <100, Kim, ...> 터플이 변경되면, teaches 테이블에서 참조하는 터플로 인하여 참조 무결성이 위배된다.
이 경우, 행동이 명시되지 않았으면 ( on update
다음에 아무것도 없으면 ) 아예 변경 연산이 허용되지 않으며,
cascade인 경우에는 변경 연산이 teaches 테이블에 파급되어 변경된 터플을 참조하는 두 터플이 모두 변경된다.
<100, CS101,...>
과 <100, CS201, ...>
이 변경)set null 은 해당 테이블 속성 값을 널 값으로 한다. 즉, on update set null
을 적어주었고, pID가 100인 교수가 변경될 경우 <null, CS101>
, <null, CS201>
이 된다.
(pID, cID, semester, year)
이었다.on delete와 다르게 on update의 경우에서 참조하는 테이블, teaches의 터플을 주키에 있지 않은 놈으로 변경하는 것은 참조 무결성 제약을 위배하므로(참조하는 놈이 참조되는 놈 안에 포함되지 않으므로) 허용되지 않는다.
IV. 외래키가 있는 상태에서 어떻게 튜플을 삽입할까?
Create table person (
ID char(10) primary key,
name char(40),
mother char(10),
father char(10),
foreign key (mother) references person,
foreign key (father) references person
);
person 테이블이 상기와 같이 정의되었다고 가정하자. 단일 관계에 존재하는 참조 무결성 제약 예제이다.
mother와 father 속성이 외래 키로 선언이 되어 있으므로, person 데이터를 입력하려면 그 사람에 대한 mother, father 정보가 있어야 한다.
이를 해결하는 방법 중에서
첫 번째 방법은
두 번째 방법은
세 번째 방법은
연기된 무결성 제약
무결성 제약은 기본적으로는 즉시 실행되나,
무결성 제약을 명시할 때 initially deferred
표현을 하면 무결성 제약 검사 및 행동을 연기할 수도 있다.
또한 트랜잭션 정의 시에 set constraints constraints-list deferred
로 무결성 제약 점검을 연기할 수도 있다.
앞에서 살펴본 무결성 제약 외에 사용자가 임의로 정의하는 복잡한 무결성 제약을 지원하는 방법은 check절
조건을 활용하거나 또는 주장(assertion
) 기능을 활용하는 것이다.
Create teaches (
pID char(5) CHECK (pID IN (select pID from professor))
…
);
SQL표준은 check 조건에 임의의 조건을 허용하므로, 상기 예제와 같이 서브질의를 조건으로 할 수 있다. 상기 예제의 의미는 teaches pID 값은 professor pID 값 중에 하나를 가지는 참조 무결성이다
그러나 이 경우에는 무결성 제약 만족 여부를 teaches 테이블에 변화가 있을 때만으로 한정을 하여 professor 테이블에 변화가 있어도 무결성 제약을 점검하지 않는 문제가 있다.
그리고, 주장(assertion)은 표준 SQL2에 명시되어 있는 사양이며, 사용자 임의의 무결성 제약을 유지하는 방법이다.
일반적으로 상용 데이터베이스 시스템은 check 절에 서브질의를 허용하지 않으며 또한 주장(assertion) 기능을 지원하지 않는다. 그 이유는 check 절 서브질의 및 주장(assertion)을 유지하는 많은 비용이 들어가며 동시에 시스템 성능을 저하시키는 요인이 되기 때문이다.
Create assertion myVerifyTotalCredit check
(not exists
(select s1.sID
from student s1
where s1.totalCredit <> (select sum(credit)
from takes, course
where s1.sID = sID
and course.cID=takes.cID
and grade is not null
and grade <> ‘F’)
)
);
상기 예제는 student 테이블의 totalCredit 속성 값을 점검하는 assertion이다. takes 테이블에서 grade가 널 값이 아니고 ‘F’가 아니면 정상적으로 수업을 수강하고 학점을 받은 과목이므로 이들 과목의 credit 속성 합산은 student 테이블의 totalCredit 속성값과 일치하여야 한다.
참고적으로 SQL 언어는 전체정량자(∀, for all)를 제공하지 않으므로, (∀x) P(x) 표현 대신에 ¬(∃x) ¬(P(x)) 표현을 사용하여 표현하여야 한다.
상기 예제에서 언급되는 테이블(여기서는 student, takes, course)에 대한 변화(데이터 입력, 삭제, 변경)가 있으면 데이터베이스 시스템은 무결성 제약 만족 여부를 매번 점검해야 한다. 즉 데이터베이스 시스템은 세 개 테이블에 대한 변화가 있을 때마다 not exists 조건을 점검해야 하는데, 자원이 많이 소모되는 연산이다.
assertion 기능은 자원 낭비가 많아, 무결성 제약 관리를 위하여 상용 데이터베이스 시스템은 주장 대신에 트리거(trigger)를 제공하고 있다.