# 27강. 제약
`CREATE TABLE`로 테이블을 정의할 경우, 열 이외에 제약도 정의할 수 있었다. 그중 하나가 바로 `NOT NULL` 제약이다. `NOT NULL` 이외에도 다양한 제약에 대해서 알아본다.

- 테이블에 제약을 설정함으로써 저장될 데이터를 제한할 수 있다.
- 예를 들어 `NOT NULL` 제약은 `NULL` 값이 저장되지 않도록 제한한다.
- `NOT NULL` 제약 외에도 `기본키(Primary Key)` 제약이나 `외부참조(정합)` 제약 등이 있다.
    - 복수의 테이블 사이에서 정합성을 유지하기 위해 설정하는 것으로 테이블 간에는 부모 자식과 같은 관계를 가지며 정합성을 유지한다.
    - 자식 테이블 측에서는 `외부키(FOREIGN KEY)`를 지정해 부모 테이블을 참조한다.
    - 부모 테이블에서 참조될 열은 반드시 `유일성(UNIQUE KEY, PRIMARY KEY)`을 가진다.
- 이 제약은 데이터에비스 설계에도 영향을 주는 중요한 개념이다.
- 특히 기본키 제약은 `RDBMS`에서 반드시 언급되는 사항이므로 추가나 삭제 방법을 확실하게 알아두자.

---

## 1. 테이블 작성시 제약 정의
- 제약은 테이블에 설정하는 것이다.
- `CREATE TABLE`로 테이블을 작성할 때 제약을 같이 정의한다.
- 물론 `ALTER TABLE`로 제약을 지정하거나 변경할 수 있다.
- 이때 `NOT NULL` 제약 등 하나의 열에 대해 설정하는 제약은 열을 정의할 때 지정한다.
- 다음은 `NOT NULL` 제약과 `UNIQUE` 제약을 설정한 예이다.

**`테이블 열에 제약 정의하기`**
```
CREATE TABLE sample631 (
    a INTEGER NOT NULL,
    b INTEGER NOT NULL UNIQUE,
    c VARCHAR(30)
);
```

- a 열에는 `NOT NULL` 제약이 걸려있다.
- b 열에는 `NOT NULL` 제약과 `UNIQUE` 제약이 걸려있다.
- c 열에는 제약이 지정되어 있지 않다.
- 이처럼 열에 대해 정의하는 제약을 `열 제약`이라고 부른다.
- `복수열에 의한 기본키 제약`처럼 한 개의 제약으로 복수의 열에 제약을 설정하는 경우를 `테이블 제약`이라 부른다.

**`테이블에 테이블 제약 정의하기`**
```
CREATE TABLE sample632 (
    no INTEGER NOT NULL,
    sub_no INTEGER NOT NULL,
    name VARCHAR(30),
    PRIMARY KEY (no, sub_no)
);
```

- 제약에는 이름을 붙일 수 있다. 제약에 이름을 붙이면 나중에 관리하기 쉬워지므로 가능한 한 이름을 붙이도록 하자.
- 제약 이름은 `CONSTRAINT` 키워드를 사용해서 지정한다.

**`테이블 제약에 이름 붙이기`**
```
CREATE TABLE sample632 (
    no INTEGER NOT NULL,
    sub_no INTEGER NOT NULL,
    name VARCHAR(30),
    CONSTRAINT pkey_sample PRIMARY KEY (no, sub_no)
);
```

---

## 2. 제약 추가
- 기존 테이블에도 나중에 제약을 추가할 수 있다. 이때 열 제약과 테이블 제약은 조금 다른 방법으로 추가한다.

### 열 제약 추가
- 열 제약을 추가할 경우 `ALTER TABLE`로 열 정의를 변경할 수 있다.
- 기존 테이블을 변경할 경우에는 제약을 위반하는 데이터가 있는지 먼저 검사한다.
- 만약 c 열에 `NULL` 값이 존재한다면 `ALTER TABLE` 명령은 에러가 발생한다.

다음은 c 열에 `NOT NULL` 제약을 설정하는 예이다.

**`c열에 NOT NULL 제약 걸기`**
```
ALTER TABLE sample631 MODIFY c VARCHAR(30) NOT NULL;
```

### 테이블 제약 추가
- 테이블 제약은 `ALTER TABLE`의 `ADD` 하부명령으로 추가할 수 있다.
- 다음 예제는 기본키 제약을 추가하는 예이다.
- 기본키는 테이블에 하나만 설정할 수 있다. 이미 기본키가 설정되어 있는 테이블에 추가로 기본키를 작성할 수는 없다.
- 또, 열 제약을 추가할 때와 마찬가지로 기존의 행을 검사해 추가할 제약을 위반하는 데이터가 있으면 에러가 발생한다.

**`기본키 제약 추가하기`**
```
ALTER TABLE sample631 ADD CONSTRAINT pkey_sample631 PRIMARY KEY(a);
```

---

## 3. 제약 삭제
- 테이블 제약은 나중에 삭제할 수도 있다.
- 열 제약의 경우, 제약을 추가할 때와 동일하게 열 정의를 변경합니다.
- 다음은 앞서 추가한 c 열의 `NOT NULL` 제약을 삭제하는 `ALTER TABLE`의 예이다.

**`c열의 NOT NULL 제약 없애기`**
```
ALTER TABLE sample631 MODIFY c VARCHAR(30);
```

- 한편 테이블 제약은 `ALTER TABLE`의 `DROP` 하부명령으로 삭제할 수 있다.
- 삭제할 때는 제약명을 지정한다.

**`pkey_sample631 제약 삭제하기`**
```
ALTER TABLE sample631 DROP CONSTRAINT pkey_sample631;
```

- 단, 기본키는 테이블당 하나만 설정할 수 있기 때문에 다음처럼 굳이 제약명을 지정하지 않고도 삭제할 수 있다.

**`기본키 제약 삭제하기`**
```
ALTER TABLE sample631 DROP PRIMARY KEY;
```

---

## 4. 기본키
- `CREATE TABLE`, `ALTER TABLE`을 통해 제약의 정의, 추가, 삭제에 관해 알아보았다.
- `NOT NULL` 제약은 열 제약이며, 기본키 제약이 테이블 제약이라는 것도 알았다.
- 이때 `NOT NULL` 제약을 설정하려면 대상 열에는 `NULL` 값이 존재하지 않아야 한다.
- 그렇다면 기본키 제약을 설정하기 위해서는 테이블은 어떤 조건을 만족해야 할까?

**`sample634 테이블 작성하기`**
```
CREATE TABLE sample634 (
    p INTEGER NOT NULL,
    a VARCHAR(30),
    CONSTRAINT pkey_sample634 PRIMARY KEY(p)
);
```

- 열 p가 sample634 테이블의 기본키이다. 덧붙이자면 기본키로 지정할 열은 `NOT NULL` 제약이 설정되어 있어야 한다.
- 데이터베이스에는 열쇠를 뜻하는 `키(key)`라는 단어가 자주 나온다.
- `검색키`와 같이 `OO키`의 형태로 쓰이는 경우가 많다.
- 이때 검색키는 검색할 때의 키워드라고 하면 이해하기 쉽다.
- 즉, 대량의 데이터에서 원하는 데이터를 찾아낼 때 키가 되는 요소를 지정해 검색하는 것이다.
- 기본키는 테이블의 행 한 개를 특정할 수 있는 검색키이다.
- 기본키 제약이 설정된 테이블에서는 기본키로 검색했을 때 복수의 행이 일치하는 데이터를 작성할 수 없다.
- 간단히 말하면, 기본키로 설정된 열이 중복하는 데이터 값을 가지면 제약에 위반된다.

**`sample634에 행 추가하기`**
```
INSERT INTO sample634 VALUES (1, '첫째줄');
INSERT INTO sample634 VALUES (2, '둘째줄');
INSERT INTO sample634 VALUES (3, '셋째줄');
```

- `INSERT`를 사용해 sample634에 세 개의 행을 추가했는데, 이때 p 열의 값이 각각 1, 2, 3으로 중복하지 않는다.
- 여기서 이미 존재하는 값인 2로 다시 한 번 행을 추가하면 이 `INSERT` 명령은 기본키 제약에 위반되어 행을 추가할 수 없다. p 열의 값이 중복되기 때문이다.
- 그 결과 `기본키 제약에 위반된다`는 내용의 에러가 표시된다.

**`sample634에 중복하는 행 추가하기`**
```
INSERT INTO sample634 VALUES (2, '넷째줄');

ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
```

- 한편 `UPDATE` 명령을 실행할 때도 제약을 위반하는 값이 없는지 검사한다.
- 다음과 같은 `UPDATE` 명령 역시 제약에 위반되므로 실행되지 않는다.
- p가 3인 행을 2로 갱신하는 데 성공하면 `p = 2`인 열이 두 개나 존재해 버리기 때문이다.

**`sample634을 중복된 값으로 갱신하기`**
```
UPDATE sample634 SET p = 2 WHERE p = 3;

ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
```

- 이처럼 열을 기본키로 지정해 유일한 값을 가지도록 하는 구조가 바로 `기본키 제약`이다.
- 행이 유일성을 필요로 한다는 다른 의미에서 `유일성 제약`이라 불리기도 한다.

##### 기본키 제약이 설정된 열에는 중복된 값을 지정할 수 없다!

### 복수의 열로 기본키 구성하기
- 기본키 제약에는 이를 구성할 열 지정이 필요하다.
- 이때 지정된 열은 `NOT NULL` 제약이 설정되어 있어야 한다.
- 즉, 기본키로는 `NULL` 값이 허용되지 않는다.
- 또한 기본키를 구성하는 열은 복수라도 상관없다.
- 복수의 열을 기본키로 지정했을 경우, 키를 구성하는 모든 열을 사용해서 중복하는 값이 있는지 없는지를 검사한다.
- 예를 들어 a 열과 b 열로 기본키를 지정했을 경우를 생각해보자.
- 다음과 같이 a 열만을 봤을 때는 중복하는 값이 있지만, b 열이 다르면 키 전체로서는 중복하지 않는다고 간주되기 때문에 기본키 제약에 위반되지 않는다.
- 만약 이 상태에서 키가 완전히 동일한 데이터값으로 `INSERT` 명령을 실행하면 기본키 제약에 위반된다.

**`a 열과 b 열로 이루어진 기본키`**
```
SELECT a, b FROM sample635;
```

|a|b|
|-|-|
|1|1|
|1|2|
|1|3|
|2|1|
|2|2|

---
