hyeonga_code
Database_54_SQL 제약 조건_Constraint( Not null, Unique, Primary Key, Foreign Key, Check) 본문
Database_54_SQL 제약 조건_Constraint( Not null, Unique, Primary Key, Foreign Key, Check)
hyeonga 2023. 8. 10. 05:59-- 제약 조건_Constraint
/*
CREATE TABLE [schema.]table (
column datatype [DEFAULT expr],...,
[ table_constraint ] );
*/
-- '테이블 이름'_'컬럼 이름'_'제약 조건'
-- 테이블 레벨로 규칙을 적용합니다.
-- 종속된 테이블의 삭제를 방지합니다.
-- 유효한 제약 조건 유형
-- NOT NULL
-- 해당 열에 널 값을 사용할 수 없습니다.
-- 열 레벨로만 지정할 수 있습니다.
-- DESC/DESCRIBE에서 확인할 수 있습니다.
/*
column datatype NOT NULL : 시스템이 이름을 지정합니다.
column datatype CONSTRAINT constraint_name : 사용자가 이름을 지정합니다.
*/
-- UNIQUE
-- 열 또는 열의 집합의 모든 값이 고유하게 유지되도록 합니다.
-- 한 테이블에 있는 두 행은 지정된 열 또는 열 집합에서 중복된 값을 가질 수 없습니다.
-- 널 값이 허용됩니다.
-- 널 값은 어떠한 값과도 동일한 것으로 취급되지 않습니다.
-- 여러 개가 존재할 수 있습니다.
-- 널 값을 허용하지 않기 위해서 NOT NULL 제약 조건을 추가할 수 있습니다.
-- UNIQUE 인덱스가 자동으로 생성됩니다.
/*
CONSTRAINT constraint_name UNIQUE(column) : 테이블 레벨 제약 조건입니다.
*/
-- PRIMARY KEY
-- 테이블 당 하나만 지정이 가능합니다.
-- 테이블의 각 행을 고유하게 식별합니다.
-- 열 또는 열의 조합에 고유성을 부여하며 기본 키에 속하는 열이 널 값을 가질 수 없도록 합니다.
-- PRIMARY KEY 열에 대해서는 UNIQUE 인덱스가 자동으로 생성됩니다. *****
-- 열 레벨 또는 테이블 레벨로 정의합니다.
/*
CONSTRAINT constraint_name PRIMARY KEY(column) : 테이블 레벨 제약 조건
*/
-- FOREIGN KEY
-- 동일한 테이블이나 다른 테이블에 있는 기본 키와의 관계를 설정합니다.
-- 참조무결성 제약 조건이라고 합니다.
-- 부모 테이블 : 기본키를 포함한 테이블
-- 자식 테이블 : 외래키를 포함한 테이블
-- 외래키 값은 부모 테이블의 기존 값과 일치하거나 NULL 값이어야 합니다.
-- 키워드
-- FOREIGN KEY : 테이블 제약 조건 레벨로 자식 테이블의 열을 정의합니다.
-- REFERENCES : 부모 테이블 및 부모 테이블에서의 해당 열을 식별합니다.
-- ON DELETE CASCADE : 부모 테이블의 행이 삭제되는 경우 자식 테이블의 종속 행을 삭제합니다.
-- ON DELETE SET NULL : 종속 외래 키 값을 널로 변환합니다.
-- ON DELETE : 부모 키를 지운다면이라는 뜻입니다.
-- 작성하지 않는 경우 자식 테이블이 삭제되지 않는 이상 부모 테이블을 삭제할 수 없습니다.
-- 작성하는 경우 부모 테이블만 삭제됩니다.
/*
-- SET NULL
-- 고객 테이블
-- 고객 아이디 (PK)
-- 주문 테이블
-- 주문 고객 (FK)
-- 고객 아이디를 외래키로 사용하는 주문 테이블이 존재하므로 고객이 탈퇴할 수 없습니다.
-- ON DELETE SET NULL로 작성하여 고객이 탈퇴하는 경우 고객 아이디만 NULL 값으로 수정합니다.
-- CASCADE
-- 직원 테이블
-- 기사 정보
-- 기사 차량 정보
-- 차량 지원
-- 지원 차량 정보 (FK)
-- 기사가 퇴사를 하는 경우 지원을 하던 차량 정보에서도 데이터를 삭제해야 합니다.
-- ON DELETE CASCADE로 작성하여 기사가 퇴사하는 경우 차량 정보도 삭제합니다.
*/
-- CHECK
-- 제약 조건 생성 시기
-- 테이블이 생성될 때 : CREATE
-- 테이블이 생성된 후 : ALTER
-- 지침
-- 제약 조건에 이름을 지정하지 않는 경우 Oracle Server가 SYS_Cn 형식의 이름을 생성합니다.
-- 열 레벨 도는 테이블 레벨로 제약 조건을 정의합니다.
-- 데이터 딕셔너리에서 테이블에 정의된 제약 조건을 볼 수 있습니다.
-- 정의
-- 컬럼 레벨 제약 조건 : 컬럼 선언 시 옆에 [ 제약 조건 ]작성합니다.
-- 테이블 레벨 제약 조건 : 테이블 생성 시 마지막에 [ CONSTARINT + 제약 조건 ]작성합니다.
---------------------------------------------------------------------------------------------------------------
-- 후보키 : UNIQUE + NOT NULL
-- 외래키 : 어떤 기본 키를 참조하는 키입니다.
---------------------------------------------------------------------------------------------------------------
SELECT table_name, constraint_name, constraint_type, search_condition
FROM user_constraints
WHERE table_name='EMPLOYEES';
/*
TABLE_NAME CON_NAME CON_TYPE SEARCH_CONDITION
-----------------------------------------------------------------------------------------------------------------
EMPLOYEES EMP_LAST_NAME_NN C "LAST_NAME" IS NOT NULL
EMPLOYEES EMP_EMAIL_NN C "EMAIL" IS NOT NULL
EMPLOYEES EMP_HIRE_DATE_NN C "HIRE_DATE" IS NOT NULL
EMPLOYEES EMP_JOB_NN C "JOB_ID" IS NOT NULL
EMPLOYEES EMP_SALARY_MIN C salary > 0
EMPLOYEES EMP_EMP_ID_PK P ( null )
EMPLOYEES EMP_EMAIL_UK U ( null )
EMPLOYEES EMP_JOB_FK R ( null )
EMPLOYEES EMP_DEPT_FK R ( null )
-- NOT NULL / CHECK 는 묶어 C로 표기됩니다.
-- SEARCH_CONDITION을 같이 확인해야 합니다.
*/
-- 데이터 확인
DESC user_cons_columns;
/*
이름 널? 유형
--------------- -------- --------------
OWNER NOT NULL VARCHAR2(30)
CONSTRAINT_NAME NOT NULL VARCHAR2(30)
TABLE_NAME NOT NULL VARCHAR2(30)
COLUMN_NAME VARCHAR2(4000)
POSITION NUMBER
*/
SELECT table_name, column_name, constraint_name
FROM user_cons_columns
WHERE table_name='EMPLOYEES';
/*
TABLE_NAME COLUMN_NAME CONSTRAINT_NAME
---------------------------------------------------------------------------------------
EMPLOYEES LAST_NAME EMP_LAST_NAME_NN
EMPLOYEES EMAIL EMP_EMAIL_NN
EMPLOYEES HIRE_DATE EMP_HIRE_DATE_NN
EMPLOYEES JOB_ID EMP_JOB_NN
EMPLOYEES SALARY EMP_SALARY_MIN
EMPLOYEES EMPLOYEE_ID EMP_EMP_ID_PK
EMPLOYEES EMAIL EMP_EMAIL_UK
EMPLOYEES JOB_ID EMP_JOB_FK
EMPLOYEES DEPARTMENT_ID EMP_DEPT_FK
*/
-- 조인을 사용하여 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name='EMPLOYEES';
/*
TABLE_NAME COL_NAME CON_NAME CON_TYPE SEARCH_CONDITION
--------------------------------------------------------------------------------------------------------------------------
EMPLOYEES LAST_NAME EMP_LAST_NAME_NN C "LAST_NAME" IS NOT NULL
EMPLOYEES EMAIL EMP_EMAIL_NN C "EMAIL" IS NOT NULL
EMPLOYEES HIRE_DATE EMP_HIRE_DATE_NN C "HIRE_DATE" IS NOT NULL
EMPLOYEES JOB_ID EMP_JOB_NN C "JOB_ID" IS NOT NULL
EMPLOYEES SALARY EMP_SALARY_MIN C salary > 0
EMPLOYEES EMPLOYEE_ID EMP_EMP_ID_PK P ( null )
EMPLOYEES EMAIL EMP_EMAIL_UK U ( null )
EMPLOYEES JOB_ID EMP_JOB_FK R ( null )
EMPLOYEES DP_ID EMP_DEPT_FK R ( null )
*/
-- 테이블을 생성합니다.
CREATE TABLE dept (
-- 컬럼 레벨
deptno NUMBER(4) PRIMARY KEY,
deptname VARCHAR2(20) NOT NULL UNIQUE,
create_date DATE CONSTRAINT dept_credate_nn NOT NULL,
loc VARCHAR2(50),
-- 테이블 레벨 : 어떤 컬럼의 제약인지 ( )안에 작성합니다.
CONSTRAINT dept_loc_uk UNIQUE(loc)
);
/*
Table DEPT이(가) 생성되었습니다.
*/
-- 테이블이 생성되었는지 확인합니다.
DESC dept;
/*
이름 널? 유형
----------- -------- ------------
DEPTNO NOT NULL NUMBER(4)
DEPTNAME NOT NULL VARCHAR2(20)
CREATE_DATE NOT NULL DATE
LOC VARCHAR2(50)
*/
-- 제약 조건이 생성되었는지 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name='DEPT';
-- 이름을 따로 지정하지 않은 컬럼은 'SYS_'로 시작하는 이름을 시스템이 자동으로 지정합니다.
-- 참조 외래키
-- dept 테이블을 참조하는 emp 테이블을 생성합니다.
CREATE TABLE emp (
empid NUMBER(6) CONSTRAINT emp_id_pk PRIMARY KEY,
emp_name VARCHAR2(20) NOT NULL,
email VARCHAR2(25) NOT NULL,
salary NUMBER(8, 2) NOT NULL,
hire_date DATE,
deptno NUMBER(4) REFERENCES dept(deptno), -- 외래키로 사용할 기본 키를 작성합니다.
-- 참조할 테이블의 컬럼이 기본키로 정의되어 있지 않는 경우 테이블이 생성되지 않습니다.
-- dept 테이블은 자식 테이블로 emp가 존재하므로 테이블을 삭제할 수 없습니다.
-- 테이블은 참조하는 순으로 생성하고 역순으로 삭제해야 합니다.
CONSTRAINT emp_id_email_uk UNIQUE (empid, email), -- 두 개 이상의 열을 묶어 제약 조건을 작성합니다.
-- 각 하나만 중복되는 것은 상관이 없으나 두 컬럼 값이 모두 일치하면 오류가 발생합니다.
CONSTRAINT emp_sal_ck CHECK (salary BETWEEN 2500 AND 30000)
);
/*
Table EMP이(가) 생성되었습니다.
*/
-- 제약 조건이 생성되었는지 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name='EMP';
-- 외래키는 R로 표기됩니다.
-- dept 테이블과 emp 테이블을 의 제약조건을 한 번에 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name IN ('EMP', 'DEPT');
-- 부서 테이블에 정보를 입력합니다.
INSERT INTO dept
VALUES (10, '총무', sysdate, '서울');
/*
1 행 이(가) 삽입되었습니다.
*/
INSERT INTO dept
VALUES (20, '영업', sysdate, '부산');
/*
1 행 이(가) 삽입되었습니다.
*/
-- 커밋합니다.
COMMIT;
/*
커밋 완료.
*/
-- 직원 테이븛에 정보를 입력합니다.
INSERT INTO emp
VALUES (1, 'name01', 'user', 7000, sysdate, 30);
/*
<오류>----------------------------------------------------------------------------------
오류 보고 -
ORA-02291: integrity constraint (HR.SYS_C007093) violated - parent key not found
------------------------------------------------------------------------------------------
*/
INSERT INTO emp
VALUES (1, 'name02', 'user', 700, sysdate, 10);
/*
<오류>-----------------------------------------------------
오류 보고 -
ORA-02290: check constraint (HR.EMP_SAL_CK) violated
-------------------------------------------------------------
*/
INSERT INTO emp
VALUES (1, 'name03', 'user', 7000, sysdate, 10);
/*
1 행 이(가) 삽입되었습니다.
*/
INSERT INTO emp
VALUES (2, 'name04', 'user', 24000, sysdate, 20);
/*
1 행 이(가) 삽입되었습니다.
*/
-- name03과 name04는 EMAIL 값이 동일하게 user 이지만 EMPID가 달라 UNIQUE 키에 적합합니다.
-- 커밋합니다.
COMMIT;
/*
커밋 완료.
*/
-- 부서 테이블을 조회합니다.
SELECT * FROM dept;
/*
DEPTNO DEPTNAME CREATE_DATE LOC
--------------------------------------------------------------
10 총무 23/08/03 서울
20 영업 23/08/03 부산
*/
-- 직원 테이블을 조회합니다.
SELECT * FROM emp;
/*
EMPID EMP_NAME EMAIL SALARY HIRE_DATE DEPTNO
----------------------------------------------------------------------------------------
1 name03 user 7000 23/08/03 10
2 name04 user 24000 23/08/03 20
*/
DELETE FROM dept
WHERE deptno=10;
/*
<오류>------------------------------------------------------------------------------
오류 보고 -
ORA-02292: integrity constraint (HR.SYS_C007093) violated - child record found
--------------------------------------------------------------------------------------
*/
-- ON DELETE 절을 작성하지 않고 삭제하고 싶은 경우 자식 테이블의 정보부터 수정하거나 삭제해야 합니다.
UPDATE emp
SET deptno=20;
/*
2개 행 이(가) 업데이트되었습니다.
*/
DELETE FROM dept
WHERE deptno=10;
/*
1 행 이(가) 삭제되었습니다.
*/
-- 롤백합니다.
ROLLBACK;
/*
롤백 완료.
*/
-- 테이블 제약 조건 관리
-- ALTER TABLE 문을 사용합니다.
-- 추가
/*
ALTER TABLE table
ADD [ CONSTRAINT constraint ] type (column)
*/
-- 삭제
/*
ALTER TABLE table
DROP [ CONSTRAINT constraint ] type (column)
*/
-- 활성화
/*
ALTER TABLE table
ENABLE [ CONSTRAINT constraint ] type (column)
*/
-- 비활성화
/*
ALTER TABLE table
DISABLE [ CONSTRAINT constraint ] type (column)
*/
-- 제약 조건을 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name='EMP';
-- 제약 조건의 이름을 지정하여 테이블을 삭제합니다.
ALTER TABLE emp
DROP CONSTRAINT emp_id_email_uk;
/*
Table EMP이(가) 변경되었습니다.
-- 컬럼 명일 지정한 경우 지정한 컬럼명으로 삭제할 수 있습니다.
-- 자동으로 시스템이 지정한 이름이라면 조회하여 삭제해야 합니다.
*/
-- 제약 조건을 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name='EMP';
-- 시스템 지정 이름 컬럼 삭제
ALTER TABLE emp
DROP CONSTRAINT SYS_C007373;
/*
Table EMP이(가) 변경되었습니다.
*/
-- 제약 조건을 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name='EMP';
/*
TABLE_NAME COLUMN_NAME CON_NAME CON_TYPE SEARCH_CONDITION
--------------------------------------------------------------------------------------------------------------------------------
EMP EMAIL SYS_C007368 C "EMAIL" IS NOT NULL
EMP SALARY SYS_C007369 C "SALARY" IS NOT NULL
EMP SALARY EMP_SAL_CK C salary BETWEEN 2500 AND 30000
EMP EMPID EMP_ID_PK P ( null )
*/
-- 부서를 삭제합니다.
DELETE FROM dept
WHERE deptno=10;
/*
1 행 이(가) 삭제되었습니다.
*/
-- 직원의 부서를 변경합니다.
UPDATE emp
SET deptno=100;
/*
2개 행 이(가) 업데이트되었습니다.
*/
ROLLBACK;
/*
롤백완료.
*/
-- 기본 키는 테이블 당 하나뿐이므로 지정하여 삭제할 수 있습니다.
-- 기본 키를 삭제하는 경우 참조하는 키로 사용을 많이 하고 있으므로 오류가 많이 발생합니다.
-- CASCADE와 같이 사용하는 경우가 많습니다.
ALTER TABLE emp
DROP primary key;
/*
Table EMP이(가) 변경되었습니다.
*/
ROLLBACK;
/*
롤백완료.
*/
-- 제약 조건을 추가합니다.
ALTER TABLE emp
ADD primary key(empid);
/*
Table EMP이(가) 변경되었습니다.
*/
-- 제약 조건을 확인합니다.
SELECT c.table_name, cc.column_name, c.constraint_name, c.constraint_type, c.search_condition
FROM user_constraints c JOIN user_cons_columns cc
ON (c.constraint_name = cc.constraint_name)
WHERE c.table_name='EMP';
/*
TABLE_NAME COLUMN_NAME CON_NAME CON_TYPE SEARCH_CONDITION
--------------------------------------------------------------------------------------------------------------------------------
EMP EMAIL SYS_C007368 C "EMAIL" IS NOT NULL
EMP SALARY SYS_C007369 C "SALARY" IS NOT NULL
EMP SALARY EMP_SAL_CK C salary BETWEEN 2500 AND 30000
EMP EMPID EMP_ID_PK P ( null )
*/
-- 삭제 시 기존 값을 NULL 값으로 변경합니다.
ALTER TABLE emp
ADD CONSTRAINT emp_deptno_fk FOREIGN KEY(deptno)
REFERENCES dept(deptno)
ON DELETE SET NULL;
/*
Table EMP이(가) 변경되었습니다.
*/
-- 직원 정보를 조회합니다.
SELECT * FROM emp;
/*
EMPID EMP_NAME EMAIL SALARY HIRE_DATE DEPTNO
-----------------------------------------------------------------------------------
1 name03 user 7000 23/08/03 10
2 name04 user 24000 23/08/03 20
*/
'Oracle Database' 카테고리의 다른 글
Database_56_데이터베이스 객체_뷰_VIEW (0) | 2023.08.12 |
---|---|
Database_55_SQL 데이터베이스 객체 (0) | 2023.08.11 |
Database_53_SQL 테이블 삭제, 휴지통_DROP TABLE, RECYCLE BIN (0) | 2023.08.09 |
Database_52_SQL 테이블 수정_ALTER TABLE (0) | 2023.08.08 |
Database_51_SQL 오라클 데이터 유형, 테이블 생성_숫자, 날짜, 문자, 이진 (0) | 2023.08.07 |