
💡 CONSTRAINTS(제약조건) 이란?
: 제약조건으로 테이블에 데이터가 입력되거나 수정될 경우에 발생하는 규칙
: 데이터 무결성 보장

💡 NULL 값을 허용하지 않는 제약조건
1) NOTNULL 조건을 포함한 테이블 생성
<코드>
-- 테이블 생성 (NOT NULL 제약조건 포함)
CREATE TABLE if NOT EXISTS user_notnull(
user_no INT NOT NULL,
user_id VARCHAR(255) NOT NULL,
user_pwd VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3),
phone VARCHAR(255) NOT NULL,
email VARCHAR(255)
) ENGINE = INNODB;
-- 조회
DESC user_notnull;
<실행결과>

2) 생성된 테이블에 NULL값 넣어보기
<코드>
-- NOTNULL 제약조건을 가진 행에 NULL값 대입
INSERT
INTO user_notnull
(user_no, user_id, user_pwd, user_name, gender, phone, email)
VALUES
( 3, 'user03', 'pass03', NULL , '남', '010-1234-5678', 'hong123@gmail.com');
<실행결과>

💡 중복값 을 허용하지 않는 제약조건
1) UNIQUE 조건을 포함한 테이블 생성
<코드>
-- 테이블 생성(UNIQUE 제약조건 포함)
CREATE TABLE if NOT EXISTS user_unique(
user_no INT NOT NULL UNIQUE,
user_id VARCHAR(255) NOT NULL,
user_pwd VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3),
phone VARCHAR(255) NOT NULL,
email VARCHAR(255),
UNIQUE(phone)
) ENGINE = INNODB;
-- 조회
DESC user_unique;
<실행결과>

2) 생성된 테이블에 중복값 넣어보기
<코드>
-- PHONE 컬럼에 중복값을 대입
INSERT
INTO user_unique
(user_no, user_id, user_pwd, user_name, gender, phone, email)
VALUES
( 1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@gmail.com'),
( 2, 'user02', 'pass02', '유관순', '여', '010-777-7777', 'yu77@gmail.com'),
( 3, 'user03', 'pass01', '홍길동2' , '남', '010-1234-5678', 'hong123@gmail.com');
<실행결과>

💡 특정 레코드를 유일하게 식별(식별자) 하기 위해 사용되는 컬럼
💡 PRIMARY KEY 특성
1. 테이블에서 한 행의 정보를 찾기 위해 사용할 컬럼
2. 테이블에 대한 식별자 역할
3. PK = NOT NULL + UNIQUE 제약조건
4. 테이블 1개당 1개만 설정 (1개는 필수)
5. Column-Level/ Table-Level 둘다 설정 가능
6. 한 개 컬럼에 설정 가능 / 여러 개 컬럼에 묶어서 설정 가능(복합키: Table-Level만 설정)
1) PRIMARY KEY 조건을 포함한 테이블 생성
<코드>
-- 테이블 생성 (PRIMARY KEY 포함)
CREATE TABLE if NOT EXISTS user_primarykey(
-- user_no INT PRIMARY KEY ,
user_no INT,
user_id VARCHAR(255) NOT NULL,
user_pwd VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3),
phone VARCHAR(255) NOT NULL,
email VARCHAR(255),
UNIQUE(phone),
PRIMARY KEY(user_no)
) ENGINE = INNODB;
-- 조회
DESC user_primarykey;
<실행결과>

2) 생성된 테이블에 NULL값 넣어보기
<코드>
-- PK에 해당하는 'user_no' 컬럼에 NULL값 대입
INSERT
INTO user_primarykey
(user_no, user_id, user_pwd, user_name, gender, phone, email)
VALUES
(null, 'user03', 'pass03', '이순신', '남', '010-777-7777', 'lee222@gmail.com');
<실행결과>

3) 생성된 테이블에 중복값 넣어보기
<코드>
-- PK에 해당하는 'user_no' 컬럼에 중복값 대입
INSERT
INTO user_primarykey
(user_no, user_id, user_pwd, user_name, gender, phone, email)
VALUES
(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@gmail.com'),
(2, 'user02', 'pass02', '유관순', '여', '010-777-7777', 'yu77@gmail.com'),
(1, 'user012', 'pass012', '홍길동2', '남2', '010-1234-5678', 'hong1232@gmail.com');
<실행결과>

💡 다른 테이블의 PK에 참조 되는 KEY
💡 FOREIGN KEY 선언 방법
1. 서로 JOIN 할 필요가 있는 2개의 테이블을 선정
2. 2개의 테이블 간에 각각 개념적으로 몇 대 몇으로 매핑되는지 판단 (카디널리티)
3. 1:N 형식으로 매핑이 된다면, 1은 부모, N은 자식 테이블
4. 부모 테이블 에서 PK 를 자식 테이블에서 FK 로 참조되며 FK 선언
💡 FOREIGN KEY 의 특성
1. 참조 무결성 을 위배하지 않기 위해 사용
2. 참조(REFERENCES) 된 다른 테이블의 컬럼에 존재하는 값만 사용 가능( 그 외는 NULL만 사용 가능)
3. PK와 FK를 통해서 테이블 간의 관계(RelationShip) 형성
4. 삭제룰(FOREIGN KEY에 붙여서 씀) 에 따라 달라짐

1) 테이블 생성 (PK -FK 관계를 가진 2개의 테이블)
<코드>
-- 4-1. 회원용 부모 테이블 생성 (PK)
CREATE TABLE if NOT EXISTS user_grade (
grade_code INT NOT NULL UNIQUE,
grade_name VARCHAR(255) NOT NULL
);
-- 4-2. 회원용 자식 테이블을 생성 (FK)
CREATE TABLE if NOT EXISTS user_foreignkey1 (
user_no INT PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
user_pwd VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3),
phone VARCHAR(255) NOT NULL,
email VARCHAR(255),
grade_code INT,
FOREIGN KEY(grade_code) REFERENCES user_grade(grade_code)
) ENGINE = INNODB;
-- 조회
DESC user_foreignkey1;
<실행결과>

2) 참조된 컬럼에 없는 값(NULL)을 넣어보기
<코드>
-- 부모 테이블인 user_grade에 초기값 대입
INSERT
INTO user_grade
VALUES
(10, '일반회원'),
(20, '우수회원'),
(30, '특별회원');
-- 자식 테이블인 user_foreignkey1에 초기값 대입
INSERT
INTO user_foreignekey1
VALUES
(3, 'user01', 'pass01', '홍길동', '남', '010-111-2222', 'hong@gmail.com', NULL);
<실행결과>

3) 참조된 컬럼에 없는 값을 넣어보기
<코드>
-- 참조된 PK에 없는 값(NULL제외) 대입
INSERT
INTO user_foreignekey1
VALUES
(4, 'user02', 'pass02', '유관순', '여', '010-333-2123', 'yu@gmail.com', 40);
<실행결과>

4) 참조된 부모테이블의 컬럼 삭제
<코드>
-- 자식 테이블에 참조되어 있는 값(10)
DELETE
FROM user_grade
WHERE grade_code = 10;
<실행결과>

4-1) 참조된 부모테이블의 컬럼 삭제( 자식테이블 먼저 삭제 )
<코드>
-- 자식 테이블 해당 컬럼 통으로 삭제
DELETE
FROM user_foreignkey1
WHERE grade_code = 10;
-- 부모 테이블 해당 컬럼 통으로 삭제
DELETE
FROM user_grade
WHERE grade_code = 10;
<실행결과>

4-2) 삭제룰을 통해서 삭제하기 (ON DELETE CASCADE)
<코드>
-- 삭제룰(ON DELETE CASCADE)를 삽입한 테이블 생성
CREATE TABLE if NOT EXISTS user_foreignkey1 (
user_no INT,
user_id VARCHAR(255) NOT NULL,
user_pwd VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3),
phone VARCHAR(255) NOT NULL,
email VARCHAR(255),
grade_code INT,
PRIMARY KEY(user_no),
FOREIGN KEY(grade_code) REFERENCES user_grade(grade_code)
ON DELETE CASCADE
) ENGINE = INNODB;
-- 부모 테이블인 user_grade에서 삭제
DELETE
FROM user_grade
WHERE grade_code = 20;
-- 조회
SELECT * FROM user_foreignkey1;
<실행결과>

4-3) 삭제룰을 통해서 삭제하기 (ON DELETE SET NULL)
<코드>
-- 삭제룰(ON DELETE SET NULL)을 삽입한 테이블 생성
CREATE TABLE if NOT EXISTS user_foreignkey2(
user_no INT PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
user_pwd VARCHAR(255) NOT NULL,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3),
phone VARCHAR(255) NOT NULL,
email VARCHAR(255),
grade_code INT,
FOREIGN KEY(grade_code) REFERENCES user_grade(grade_code)
ON DELETE SET NULL
) ENGINE = INNODB;
-- 테이블에 삽입
INSERT
INTO user_foreignkey2
VALUES
(1, 'user02', 'pass02', '유관순', '여', '010-333-2123', 'yu@gmail.com', 10);
-- user_grade 부모 테이블과 연결되어 있는 기존 자식 테이블 초기화
TRUNCATE user_foreginkey1;
--참조하는 부모 테이블의 행 삭제 후 참조 컬럼 값 확인
DELETE FROM user_grade WHERE grade_code = 10;
-- 조회
SELECT * FROM user_foreignkey2;
<실행결과>

💡 위반시 오류가 발생하는 제약 조건
1) Check 제약조건에 맞는 값 대입
<코드>
-- check 제약조건을 가진 테이블 생성
DROP TABLE if EXISTS user_check;
CREATE TABLE if NOT EXISTS user_check (
USER_no INT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3) CHECK(gender IN ('남', '여')),
age INT CHECK(age >= 19)
) ENGINE = INNODB;
-- check 제약조건에 성립되는 값 대입
INSERT
INTO user_check
VALUES
(NULL, '홍길동', '남', 25),
(NULL, '이순신', '남', 33);
<실행결과>

2) Check 제약조건에 맞지 않는 값 대입
<코드>
-- check 제약조건을 가진 테이블 생성
DROP TABLE if EXISTS user_check;
CREATE TABLE if NOT EXISTS user_check (
USER_no INT AUTO_INCREMENT PRIMARY KEY,
user_name VARCHAR(255) NOT NULL,
gender VARCHAR(3) CHECK(gender IN ('남', '여')),
age INT CHECK(age >= 19)
) ENGINE = INNODB;
-- 성별에 잘못된 값 입력
INSERT
INTO user_check
VALUES
(NULL, '아메바', '중', 19);
-- 나이 조건에 부합하지 X
INSERT
INTO user_check
VALUES
(NULL, '유관순', '여', 16);
<실행결과>


💡 컬럼에 NULL값 대신 기본값(default)을 대입
<코드>
-- default 제약조건을 가진 테이블 생성
CREATE TABLE if NOT EXISTS tbl_country(
country_code INT AUTO_INCREMENT PRIMARY KEY,
country_name VARCHAR(255) DEFAULT '한국',
population VARCHAR(255) DEFAULT '0명',
add_day DATE DEFAULT (CURRENT_DATE),
add_time DATETIME DEFAULT (CURRENT_TIME)
) ENGINE = INNODB DEFAULT CHARSET UTF8;
-- NULL값 대신 DEFAULT값을 넣음
INSERT
INTO tbl_country
VALUES
(NULL, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
-- 조회
SELECT * FROM tbl_country;
<실행결과>
