앞서 DBMS가 무결성 제약조건을 검사해준다고 하였다. DBMS는 각각의 갱신 연산(CRUD)에 대하여 데이터베이스가 무결성 제약조건들을 만족하도록 필요한 조치를 취한다. DBMS는 어떠한 조치를 취해서 무결성을 유지하는 것일까?
대표적인 예시로, 14. Python ORM - Flask-SQLAlchemy에서 사용해 본 적이 있는 아래의 관계 데이터베이스 인스턴스를 사용하여 살펴보자.
post 릴레이션의 user_id 애트리뷰트가 user 릴레이션의 기본 키인 id를 참조하는 외래키이다. 그러므로 user가 참조된 릴레이션, post가 참조하는 릴레이션이 된다.
만약 기본 키나 외래 키를 수정하고자 하는 것이면 2)DELETE인 경우 옵션과 같은 방식이 적용된다.
또는 기본 키나 외래 키 이외의 애트리뷰트 값을 수정하고자 하는 것이면 참조 무결성 제약조건을 위배하지 않기 때문에 나머지 제약조건을 만족하는지만 검사한다.
SQL의 구성요소에는 데이터 정의어, 데이터 조작어, 데이터 제어어 등이 있다. 이 중 사용자는 데이터 정의어를 통해 무결성 제약조건을 포함하여 스키마를 생성할 수 있다. 그래서 데이터 정의어를 하나씩 살펴보면서 어떻게 데이터 정의어로 무결성 제약조건을 명시할 수 있는지 배워보았다.
1) 애트리뷰트의 제약 조건
릴레이션의 정의시에 다양한 제약 조건을 추가할 수 있다.
CREATE TABLE EMPLOYEE
(EMPNO INTEGER NOT NULL, #NOT NULL
EMPNAME CHAR(10) UNIQUE, #UNIQUE
TITLE CHAR(10) DEFAULT '사원', #DEFAULT
SALARY INTEGER CHECK (SALARY < 6000000), #CHECK
DNO INTEGER CHECK (DNO IN (1, 2, 3, 4, 5)), #CHECK
)
2) 기본 키 제약조건
릴레이션을 생성 할 대 기본 키 제약조건은 해당 릴레이션의 기본 키가 어떤 애트리뷰트인지 명시하고, 기본 키는 널 값을 가지지 않도록 명시해주어야 한다.
CREATE TABLE EMPLOYEE
(EMPNO INTEGER NOT NULL,
EMPNAME CHAR(10) UNIQUE,
TITLE CHAR(10) DEFAULT '사원',
SALARY INTEGER CHECK (SALARY < 6000000),
DNO INTEGER CHECK (DNO IN (1, 2, 3, 4, 5)),
PRIMARY KEY(EMPNO) #기본 키 제약조건
)
3) 참조 무결성 제약조건
참조 무결성 제약조선은 릴레이션을 정의하면서 명시하며 한 릴레이션에 들어 있는 Foreign key의 수만큼 참조 무결성 제약 조건을 명시 할 수 있다.
또한 위에서 살펴본 것처럼 DBMS의 무결성 제약조건 유지를 위해 참조되는 릴레이션의 튜플이 삭제되거나 수정 될 때, 참조하는 릴레이션에서 어떻게 동작할 것인가를 명시한다.
CREATE TABLE EMPLOYEE
(EMPNO INTEGER NOT NULL,
EMPNAME CHAR(10) UNIQUE,
TITLE CHAR(10) DEFAULT '사원',
SALARY INTEGER CHECK (SALARY < 6000000),
DNO INTEGER CHECK (DNO IN (1, 2, 3, 4, 5)),
PRIMARY KEY(EMPNO),
FOREIGN KEY(DNO) REFERENCES DEPARTMENT(DEPTNO) #참조 무결성 제약조건
ON DELETE SET DEFAULT
ON UPDATE CASCADE;
)
#참조 무결성 제약조건을 위한 데이터 정의어
ON DELETE NO ACTION
ON DELETE CASCADE
ON DELETE SET NULL
ON DELETE SET DEFAULT
ON UPDATE NO ACTION
ON UPDATE CASCADE
ON UPDATE SET NULL
ON UPDATE SET DEFAULT
4) 무결성 제약조건의 추가 및 삭제
릴레이션이 생성 된 후에도 여러 제약조건을 추가하거나 기존 제약 조건을 삭제할 수 있다.
#무결성 제약조건 추가
ALTER TABLE [릴레이션 명] ADD [제약조건]
#무결성 제약조건 삭제
ALTER TABLE [릴레이션 명] DROP [제약조건]
위에서 테이블을 정의할 때 데이터베이스 스키마의 한 부분으로서 무결성 제약조건을 명시하는 것을 알아보았다. 이제 테이블 정의와 별도로 데이터베이스의 무결성을 시행하는 메커니즘인 트리거와 주장에 대해서 정리해보고자 한다.
1) 트리거
트리거는 데이터베이스이 갱신될 때마다 DBMS가 자동적으로 수행하도록 사용자가 정의하는 문이다. 트리거는 테이블 정의시 표현할 수 없는 규칙들을 시행하며, 무결성 제약조건을 유지하기 위해 데이터베이스 갱신을 모니터링하고, 갱신을 진행한다.
**트리거는 마치 조건문처럼 한 릴레이션에 대해서 INSERT, DELETE, UPDATE 이벤트가 발생하면 트리거가 활성화되면 트리거의 조건이 참이 되면 트리거와 연관된 동작이 데이터베이스에 대해 실행되고, 그렇지 않으면 아무 동작도 수행되지 않는다.
이처럼 트리거는 제약조건과 유사하게 데이터베이스의 일관성을 유지하는데 유용하다. 그러나 트리거를 많이 사용하면 트리거들이 연쇄되어 복잡한 상호 의존성을 야기할 수도 있다. **
트리거를 명시하는 방법은
CREATE TRIGGER [트리거 이름]
ALTER [트리거를 유발하는 이벤트들이 OR로 연결된 리스트] ON [릴레이션 이름] #이벤트
(WHEN [조건]) #조건
BEGIN [SQL문들] END #동작
2) 주장
제약조건을 위반하는 연산이 수행되지 않도록 주장의 조건이 그 조건을 위배할 가능성이 있는 각 이벤트문들마다 검사된다.
주장의 명시하는 방법은
CREATE ASSERTION [주장 이름]
CHECK [조건]
주장은 데이터베이스가 항상 만족하기를 바라는 조건을 직접적으로 표현한 것으로 보통 두 개 이상의 테이블에 영향을 미치는 제약조건을 명시하기 위해 사용된다.
그러나 주장이 복잡하면 유효성검사에서도 많은 오버헤드가 발생할 수 있으므로 신중하게 사용해야 한다.
주장의 예) ENROLL 릴레이션에 들어 있는 STNO는 반드시 STUDENT 릴레이션에 들어 있는 어떤 학생의 STNO를 참조하도록 하는 주장을 정의 ( = 다시 말해 STUDENT릴레이션에 없는 학생의 학번(STNO)이 ENROLL릴레이션에 들어가면 안된다.는 주장)
CREATE ASSERTION EnrollStudentIntegrity
CHECK (NOT EXISTS
(SELECT *
FROM ENROLL
WHERE STNO NOT IN
(SELECT STNO FROM STUDENT)));
MS SQL Server 기반 데이터베이스 배움터 - 홍의경 지음