DDL(DATA DEFINITION LANGUAGE)
데이터 정의 언어
객체(OBJECT)를 만들고(CREATE), 수정(ALTER)하고, 삭제(DROP)
--> 데이터의 전체 구조를 정의하는 언어로 주로 DB관리자, 설계자가 사용함
자료형
CHAR: 고정 길이 문자열. 최대 2000 BYTE
VARCHAR: 가변 길이 문자열, 최대 2000 BYTE (한글 666자)
VARCHAR2: 가변 길이 문자열, 최대 4000 BYTE (한글 대충 1000자_ 엔터 띄어쓰기 고려)
DATE : 날짜 타입
BLOB : 대용량 이진 데이터 (4GB)
CLOB : 대용량 문자 데이터 (4GB)
UTF-8: 기본 2BYTE 크기, 가변 문자 인코딩(문자 종류에 따라 크기 달라짐
1BYTE 아스키코드 범위 문자(숫자, 알파벳, 기본 특수 문자) 입력 시
--> UTF-8은 1BYTE로 변환
2BYTE 유니코드 범위(한글 미포함)
3BYTE : 한글 유니코드 -> UTF-8 형식으로 변환 시 3BYTE로 변환됨
EX) '한'
유니코드: 1101 0111 1100 0011
UTF-8 변경: 1100 0011 0001 0101 1111 0110
JAVA-Char: 문자 1개
DB-CHAR: 고정 길이 문자 "열"
테이블
테이블 생성
CREATE TABLE 테이블명 (
컬럼명 자료형(크기),
컬럼명 자료형(크기),
...);
데이터 삽입
DEFAULT: 입력되는 값이 없거나 'DEFAULT'키워드 사용 시에 기록되어 질 값을 지정
컬럼에 주석 달기
COMMENT ON COLUMN 테이블명.컬럼명 IS '주석 내용';
테이블 삭제
DROP TABLE 테이블명
USER_TABLES: 사용자가 작성한 테이블을 확인하는 뷰
SELECT * FROM USER_TABLES;
제약조건(CONSTRAINT)
사용자가 원하는 조건의 데이터만 유지하기 위해 특정 컬럼에 설정하는 데이터 무결성 보장을 목적으로 하는 것
PRIMARY KEY
테이블에 대한 식별자 역할 (NOT NULL + UNIQUE)
한 테이블 당 한 개만 설정할 수 있고 컬럼레벨, 테이블레벨 둘 다 가능
NOT NULL
컬럼레벨 제약조건
UNIQUE
중복 제한하는 제약 조건
컬럼레벨, 테이블레벨에서 설정 가능
NULL 값은 중복 삽입 가능
CHECK
컬럼에 기록되는 값의 조건 설정 가능
비교값은 리터럴만 사용할 수 있음. 변하는 값이나 함수 사용 못함
FOREIGN KEY
다른 테이블에서 UNIQUE, PRIMARY KEY 지정된 컬럼만 참조 가능
GRADE_CODE NUMBER CONSTRAINT GRADE_CODE_FK REFERENCES USER_GRADE(GRADE_CODE)
CONSTRAINT GRADE_CODE_FK FOREIGN KEY(GRADE_CODE) REFERENCES USER_GRADE
FOREIGN KEY 삭제 옵션
SUBQUERY를 이용한 테이블 생성
컬럼명, 데이터 타입, 값이 복사되고 제약조건은 NOT NULL만 복사됨
(NOT NULL이 CHECK안에 포함되어 있기 때문에 제약조건 형태는 CHECK로 나타나있음)
제약조건 추가
ALTER TABLE EMPLOYEE_COPY ADD
CONSTRAINT PK_EMP_COPY PRIMARY KEY(EMP_ID);
ALTER TABLE DEPARTMENT ADD
CONSTRAINT FK_DEPT_ID FOREIGN KEY(DEPT_ID) REFERENCES DEPARTMENT;
-- ALTER TABLE 테이블명 ADD [CONSTRAINT 제약조건명] UNIQUE(컬럼명)
-- ALTER TABLE 테이블명 ADD [CONSTRAINT 제약조건명] CHECK(컬럼명 비교연산자 비교값)
-- ALTER TABLE 테이블명 MODIFY 컬럼명 NOT NULL;
/*
- 데이터 딕셔너리란?
자원을 효율적으로 관리하기 위한 다양한 정보를 저장하는 시스템 테이블
데이터 딕셔너리는 사용자가 테이블을 생성하거나 사용자를 변경하는 등의
작업을 할 때 데이터베이스 서버에 의해 "자동"으로 갱신되는 테이블
- user_tables: 자신의 계정이 소유한 객체 등에 관한 정보를 조회할 수 있는 딕셔너리 뷰
*/
--------------------------------------------------------------------------------------------------------------------
-- DDL(DATA DEFINITION LANGUAGE) : 데이터 정의 언어
-- 객체(OBJECT)를 만들고(CREATE), 수정(ALTER)하고, 삭제(DROP) 등
-- 데이터의 전체 구조를 정의하는 언어로 주로 DB관리자, 설계자가 사용함
-- 오라클에서의 객체 : 테이블(TABLE), 뷰(VIEW), 시퀀스(SEQUENCE),
-- 인덱스(INDEX), 패키지(PACKAGE), 트리거(TRIGGER)
-- 프로시져(PROCEDURE), 함수(FUNCTION),
-- 동의어(SYNONYM), 사용자(USER)
--------------------------------------------------------------------------------------------------------------------
-- CREATE
-- 테이블이나 인덱스, 뷰 등 다양한 데이터베이스 객체를 생성하는 구문
-- 테이블로 생성된 객체는 DROP 구문을 통해 제거할 수 있음
-- 1. 테이블 생성하기
-- 테이블이란?
-- 행(ROW)과 열(COLOMN)로 구성되는 가장 기본적인 데이터베이스 객체
-- 데이터베이스 내에서 모든 데이터는 테이블을 통해서 저장된다.
-- [표현식]
/*
CREATE TABLE 테이블명 (
컬럼명 자료형(크기),
컬럼명 자료형(크기),
...);
*/
/* 자료형
NUMBER : 숫자형(정수, 실수), 가변길이
CHAR(크기) : 고정길이 문자형 (2000BYTE)
-> ex) CHAR(10) 컬럼에 'ABC' 3BYTE 문자열만 저장해도 10BYTE 저장공간을 모두 사용.
VARCHAR2(크기) : 가변길이 문자형 (4000 BYTE)
-> ex) VARCHAR2(10) 컬럼에 'ABC' 3BYTE 문자열만 저장하면 나머지 7BYTE를 반환함.
DATE : 날짜 타입
BLOB : 대용량 이진 데이터 (4GB)
CLOB : 대용량 문자 데이터 (4GB)
*/
-- MEMBER 테이블 생성
CREATE TABLE MEMBER(
MEMBER_ID VARCHAR2(20), -- 가변 길이 문자열 20 바이트(영어, 숫자만 작성 시 20글자)
MEMBER_PWD VARCHAR2(20),
MEMBER_NAME VARCHAR2(30), -- 한글 3BYTE * 10글자 == 3BYTE
MEMBER_SSN CHAR(14), --993021-2036547
ENROLL_DATE DATE DEFAULT SYSDATE -- 기본값이 SYSDATE이다
);
-- DEFAULT: 입력되는 값이 없거나 'DEFAULT'키워드 사용 시에 기록되어 질 값을 지정
-- 만든 테이블 확인
SELECT * FROM MEMBER;
SELECT * FROM USER_TABLES; -- 딕셔너리 뷰(데이터 딕셔너리에서 일부분만 뽑아서 만든 가상 테이블)
-- 접속 창 -> 계정 클릭 -> 테이블 클릭 -> 새로고침 클릭 -> 바뀐 멤버 테이블 확인 가능
-- 2) 컬럼에 주석 달기
-- [표현식]
-- COMMENT ON COLUMN 테이블명.컬럼명 IS '주석내용';
COMMENT ON COLUMN MEMBER.MEMBER_ID IS '회원 아이디'; -- Comment이(가) 생성되었습니다.
COMMENT ON COLUMN MEMBER.MEMBER_PWD IS '회원 비밀번호';
COMMENT ON COLUMN MEMBER.MEMBER_NAME IS '회원 이름';
COMMENT ON COLUMN MEMBER.MEMBER_SSN IS '주민 등록 번호';
COMMENT ON COLUMN MEMBER.ENROLL_DATE IS '회원 가입일';
-- USER_TABLES: 사용자가 작성한 테이블을 확인하는 뷰
-- 데이터 딕셔너리에 정의되어 있음
SELECT * FROM USER_TABLES;
-- MEMBER 테이블에 샘플 데이터 삽입
INSERT INTO MEMBER VALUES('MEM01','123ABC','홍길동','990808-1234567', DEFAULT);
COMMIT;
-- 데이터 삽입 확인
SELECT * FROM MEMBER;
-- 추가 샘플 데이터 삽입
-- 가입일 -> SYSDATE를 활용
INSERT INTO MEMBER VALUES('MEM02', 'QWER1234', '김영희', '980909-2345678', SYSDATE);
COMMIT;
SELECT * FROM MEMBER;
-- 가입일 -> DEFAULT 활용(테이블 생성 시 정의된 값이 반영됨)
INSERT INTO MEMBER VALUES('MEM03', 'ASDFQWER', '박철수', '950405-1111222', DEFAULT);
COMMIT;
SELECT * FROM MEMBER;
-- 가입일 -> INSERT 시 미작성 하는 경우 -> DEFAULT 값이 반영됨
INSERT INTO MEMBER(MEMBER_ID, MEMBER_PWD, MEMBER_NAME, MEMBER_SSN)
VALUES('MEM04', '12341234', '이지연', '000101-4564567');
COMMIT;
-- 데이터 삽입 확인
SELECT * FROM MEMBER;
-- 주민등록번호의 데이터 타입을 NUMBER로 지정할 경우 문제점
CREATE TABLE MEMBER2(
MEMBER_NAME VARCHAR2(30),
MEMBER_SSN NUMBER
);
INSERT INTO MEMBER2 VALUES('홍길동',1265029874532);
SELECT * FROM MEMBER2;
INSERT INTO MEMBER2 VALUES('김영희', 0256327856954);
SELECT * FROM MEMBER2;
--> NUMBER타입 컬럼에 데이터 삽입 시 앞에 0이 있으면 사라지는 문제점이 있다
DROP TABLE MEMBER2; -- 테이블 삭제
------------------------------------------------------------------------------------
-- 제약 조건(CONSTRAINT)
/*
사용자가 원하는 조건의 데이터만 유지하기 위해서 특정 컬럼에 설정하는 제약
데이터 무결성 보장을 목적으로 함
-> 데이터 무결성: 중복 데이터 최소화, NULL 최소화 지향
+ 입력 데이터에 문제가 없는지 자동으로 검사하는 목적
+ 데이터의 수정/삭제 가능여부 검사등을 목적으로 함
--> 제약조건을 위배하는 DML 구문은 수행할 수 없음!
제약조건 종류
PRIMARY KEY, NOT NULL, UNIQUE, CHECK, FOREIGN KEY
*/
-- 제약 조건 확인
-- USER_CONSTRAINTS: 사용자가 작성한 제약조건을 확인하는 딕셔너리 뷰
DESC USER_CONSTRAINTS;
SELECT * FROM USER_CONSTRAINTS;
-- USER_CONS_COLUMNS: 제약조건이 걸려있는 컬럼을 확인하는 딕셔너리 뷰
DESC USER_CONS_COLUMNS;
SELECT * FROM USER_CONS_COLUMNS;
-- 1. NOT NULL
-- 해당 컬럼에 반드시 값이 기록되어야 하는 경우 사용
-- 삽입/수정 시 NULL 값을 허용하지 않도록 컬럼 레벨에서 제한
CREATE TABLE USER_USED_NN(
USER_NO NUMBER NOT NULL,-- 사용자 번호(무주건 있어야 함 ==NOT NULL)
--> 컬럼레벨 제약조건 설정
USER_ID VARCHAR2 (20),
USER_PWD VARCHAR2 (30),
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2 (30),
EMAIL VARCHAR2(50)
);
INSERT INTO USER_USED_NN
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
INSERT INTO USER_USED_NN
VALUES(NULL, NULL, NULL, NULL, NULL, '010-1234-5678', 'hong123@kh.or.kr');
-- ORA-01400: NULL을 ("KHJ"."USER_USED_NN"."USER_NO") 안에 삽입할 수 없습니다
-- ORA-01400 -> 오류코드
--------------------------------------------------------------------------------
-- 2. UNIQUE 제약 조건
-- 컬럼에 입력 값에 대해서 "중복을 제한"하는 제약조건
-- 컬럼 레벨에서 설정 가능, 테이블 레벨에서 설정 가능
-- 단, UNIQUE 제약조건이 설정된 컬럼에는 NULL 값이 중복 삽입 가능
-- UNIQUE 제약조건 테이블 생성
CREATE TABLE USER_USED_UK(
USER_NO NUMBER,
USER_ID VARCHAR2(20),
--USER_ID VARCHAR2(20) UNIQUE, --컬럼레벨 제약조건 설정 (제약조건명 미지정)
--USER_ID VARCHAR2(20) CONSTRAINT USER_ID_U UNIQUE,
-- 제약 조건명 지정
USER_PWD VARCHAR2(30),
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50),
-- 테이블 레벨 제약조건 설정 부분
--UNIQUE(USER_ID) -- 테이블 레벨 제약조건 설정(제약조건명 미지정)
CONSTRAINT USER_ID_U UNIQUE(USER_ID) -- 제약조건명 지정
-- 이렇게 쓰려면 미리 컬럼레벨로 USER_ID 만들어줘야 함
);
DROP TABLE USER_USED_UK; -- 테이블 삭제
INSERT INTO USER_USED_UK
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
INSERT INTO USER_USED_UK
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
--> 같은 아이디인 데이터가 이미 테이블에 있으므로 UNIQUE 제약조건에 위배되어 오류 발생
-- ORA-00001: 무결성 제약 조건(KHJ.USER_ID_U)에 위배됩니다
--> UNIQUE
INSERT INTO USER_USED_UK
VALUES(1, NULL, 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
--> 아이디에 NULL값 삽입 가능
INSERT INTO USER_USED_UK
VALUES(1, NULL, 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
--> 아이디에 NULL 값 중복으로 삽입 가능
SELECT * FROM USER_USED_UK;
-- 오류 보고에 나타나는 SYS_C008635 같은 제약 조건명으로
-- 해당 제약 조건이 설정된 테이블명, 컬럼, 제약 조건 타입 조회
SELECT UCC.TABLE_NAME, UCC.COLUMN_NAME, UC.CONSTRAINT_TYPE
FROM USER_CONSTRAINTS UC, USER_CONS_COLUMNS UCC
WHERE UCC.CONSTRAINT_NAME = UC.CONSTRAINT_NAME
AND UCC.CONSTRAINT_NAME = 'USER_ID_U'; -- 제약조건명 넣어보기
--------------------------------------------------------------------------------
-- UNIQUE 복합키
-- 두 개 이상의 컬럼을 묶어서 하나의 UNIQUE 제약조건을 설정함
--> 모든 컬럼의 값이 같아야 중복으로 취급함
--> 복합키는 테이블 레벨로만 지정할 수 있다.
CREATE TABLE USER_USED_UK2(
USER_NO NUMBER,
USER_ID VARCHAR2(20),
USER_PWD VARCHAR2(30),
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50) ,
-- 테이블 레벨 제약조건 설정
CONSTRAINT USER_ID_NAME_U UNIQUE(USER_ID, USER_NAME)
);
DROP TABLE USER_USED_UK2;
INSERT INTO USER_USED_UK2
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
INSERT INTO USER_USED_UK2
VALUES(2, 'user02', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
--> USER_ID가 다름 -> 삽입 성공
INSERT INTO USER_USED_UK2
VALUES(2, 'user02', 'pass01', '고길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
--> USER_NAME 다름 -> 삽입 성공
INSERT INTO USER_USED_UK2
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
--> 여러 컬럼을 묶어서 UNIQUE 제약조건이 설정되어 있으면
-- 두 컬럼이 모두 중복되는 값일 경우에만 오류 발생
-- ORA-00001: 무결성 제약 조건(KHJ.USER_ID_NAME_U)에 위배됩니다
SELECT * FROM USER_USED_UK2;
--------------------------------------------------------------------------------
-- 3. PRIMARY KEY(기본키) 제약조건
-- 테이블에서 한 행의 정보를 찾기 위해 사용할 컬럼을 의미함
-- 테이블에 대한 "식별자(IDENTIFIED)"역할을 함
-- NOT NULL + UNIQUE 제약조건을 의미
-- 한 테이블 당 한 개만 설정할 수 있음
-- 컬럼레벨, 테이블레벨 둘 다 설정 가능함
-- 한 게 컬럼에 설정할 수도 있고, 여러 개의 컬럼을 묶어서 설정할 수 있음(복합키)
SELECT * FROM EMPLOYEE WHERE EMP_ID = 200;
CREATE TABLE USER_USED_PK(
USER_NO NUMBER /*CONSTRAINT USER_NO_PK*/ /*PRIMARY KEY*/, --NOT NULL + UNIQUE
-- 컬럼레벨 PK 지정 /*생략 가능*/
USER_ID VARCHAR2(20),
USER_PWD VARCHAR2(30),
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50),
CONSTRAINT USER_NO_PK PRIMARY KEY(USER_NO) -- 테이블레벨 PK지정
);
DROP TABLE USER_USED_PK;
INSERT INTO USER_USED_PK
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
INSERT INTO USER_USED_PK
VALUES(1, 'user02', 'pass02', '이순신', '남', '010-5678-9012', 'lee123@kh.or.kr');
--> 기본키 중복으로 오류
-- ORA-00001: 무결성 제약 조건(KHJ.USER_NO_PK)에 위배됩니다
INSERT INTO USER_USED_PK
VALUES(NULL, 'user03', 'pass03', '유관순', '여', '010-9999-3131', 'yoo123@kh.or.kr');
--> 기본키가 NULL이므로 오류
-- ORA-01400: NULL을 ("KHJ"."USER_USED_PK"."USER_NO") 안에 삽입할 수 없습니다
--------------------------------------------------------------------------------
-- PRIMARY KEY 복합키(테이블 레벨만 가능)
CREATE TABLE USER_USED_PK2(
USER_NO NUMBER,
USER_ID VARCHAR2(20),
USER_PWD VARCHAR2(30) NOT NULL,
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50),
CONSTRAINT PK_USERNO_USERID PRIMARY KEY(USER_NO, USER_ID) -- 복합키
);
INSERT INTO USER_USED_PK2
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
INSERT INTO USER_USED_PK2
VALUES(1, 'user02', 'pass02', '이순신', '남', '010-5678-9012', 'lee123@kh.or.kr');
-- 아이디 달라서 실행
INSERT INTO USER_USED_PK2
VALUES(2, 'user01', 'pass01', '유관순', '여', '010-9999-3131', 'yoo123@kh.or.kr');
-- NO가 달라서 실행
INSERT INTO USER_USED_PK2
VALUES(1, 'user01', 'pass01', '신사임당', '여', '010-9999-9999', 'sin123@kh.or.kr');
-- 회원번호와 아이디 둘 다 중복되었을 때만 제약조건 위배 오류 발생
-- ORA-00001: 무결성 제약 조건(KHJ.PK_USERNO_USERID)에 위배됩니다
SELECT * FROM USER_USED_PK2; -- 신사임당 제외하고 다 있음
INSERT INTO USER_USED_PK2
VALUES(NULL, 'user01', 'pass01', '신사임당', '여', '010-9999-9999', 'sin123@kh.or.kr');
-- PRIMARY KEY(식별키)는 NULL이 들어갈 수 없다.
-- ORA-01400: NULL을 ("KHJ"."USER_USED_PK2"."USER_NO") 안에 삽입할 수 없습니다
-->> 복합키어도 PK이므로 NULL 불가능한
--------------------------------------------------------------------------------
-- 4. FORIEGN KEY(외부키 / 외래키) 제약조건
--> 다른 테이블에 PK 또는 UNIQUE 제약조건이 설정된 컬럼
-- 참조(REFERENCES)된 다른 테이블의 컬럼이 제공하는 값만 사용할 수 있음
-- FOREIGN KEY제약조건에 의해서 테이블간의 관계(RELATIONSHIP)가 형성됨
-- 제공되는 값 외에는 NULL을 사용할 수 있음
-- 컬럼레벨일 경우
-- 컬럼명 자료형(크기) [CONSTRAINT 이름] REFERENCES 참조할 테이블명 [(참조할컬럼)] [삭제룰]
-- 테이블레벨일 경우
-- [CONSTRAINT 이름] FOREIGN KEY (적용할컬럼명) REFERENCES 참조할테이블명 [(참조할컬럼)] [삭제룰]
--> 테이블 레벨에서만 FOREIGN KEY 단어가 사용된다!
-- * 참조될 수 있는 컬럼은 PRIMARY KEY컬럼과, UNIQUE 지정된 컬럼만 외래키로 사용할 수 있음
-- 참조할 테이블의 참조할 컬럼명이 생략이 되면, PRIMARY KEY로 설정된 컬럼이 자동 참조할 컬럼이 됨
CREATE TABLE USER_GRADE(
GRADE_CODE NUMBER PRIMARY KEY,
GRADE_NAME VARCHAR2(30) NOT NULL
);
INSERT INTO USER_GRADE VALUES (10, '일반회원');
INSERT INTO USER_GRADE VALUES (20, '우수회원');
INSERT INTO USER_GRADE VALUES (30, '특별회원');
SELECT * FROM USER_GRADE;
CREATE TABLE USER_USED_FK(
USER_NO NUMBER PRIMARY KEY,
USER_ID VARCHAR2(20) UNIQUE,
USER_PWD VARCHAR2(30) NOT NULL,
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50),
GRADE_CODE NUMBER --CONSTRAINT GRADE_CODE_FK REFERENCES USER_GRADE(GRADE_CODE)-- 컬럼레벨 FK 설정
,
CONSTRAINT GRADE_CODE_FK FOREIGN KEY(GRADE_CODE) REFERENCES USER_GRADE
);
INSERT INTO USER_USED_FK
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr', 10);
INSERT INTO USER_USED_FK
VALUES(2, 'user02', 'pass02', '이순신', '남', '010-5678-9012', 'lee123@kh.or.kr', 10);
INSERT INTO USER_USED_FK
VALUES(3, 'user03', 'pass03', '유관순', '여', '010-9999-3131', 'yoo123@kh.or.kr', 30);
INSERT INTO USER_USED_FK
VALUES(4, 'user04', 'pass04', '안중근', '남', '010-2222-1111', 'ahn123@kh.or.kr', null);
-- NULL 사용 가능
SELECT * FROM USER_USED_FK;
INSERT INTO USER_USED_FK
VALUES(5, 'user05', 'pass05', '윤봉길', '남', '010-6666-1234', 'yoon123@kh.or.kr', 50);
--> 50이라는 값은 USER_GRADE 테이블 GRADE_CODE 컬럼에서 제공하는 값이 아니므로
-- 외래키 제약 조건에 위배되어 오류 발생
-- ORA-02291: 무결성 제약조건(KHJ.GRADE_CODE_FK)이 위배되었습니다- 부모 키가 없습니다
--> 참조 무결성 위배
--------------------------------------------------------------------------------
-- *FOREIGN KEY 삭제 옵션
-- 부모 테이블의 데이터 삭제 시 자식 테이블의 데이터를
-- 어떤 식으로 처리할지에 대한 내용을 설정할 수 있다.
SELECT * FROM USER_GRADE; -- 참조를 당하는 테이블 == 부모 테이블
SELECT * FROM USER_USED_FK; -- 참조를 하는 테이블 == 자식 테이블
DELETE FROM USER_GRADE
WHERE GRADE_CODE = 10;
-- ORA-02292: 무결성 제약조건(KHJ.GRADE_CODE_FK)이 위배되었습니다- 자식 레코드가 발견되었습니다
-- 1) ON DELETE RESTIRCTED(삭제 제한)로 기본 지정되어 있음
-- FOREIGN KEY로 지정된 컬럼에서 사용되고 있는 값일 경우
-- 제공하는 컬럼의 값은 삭제하지 못함
-- GRADE_CODE 중 20은 외래키로 참조되고 있지 않으므로 삭제 가능
COMMIT;
DELETE FROM USER_GRADE
WHERE GRADE_CODE=20;
SELECT * FROM USER_GRADE;
ROLLBACK;
-- 2) ON DELETE SET NULL: 부모 키 삭제 시 자식 키를 NULL로 변경하는 옵션
CREATE TABLE USER_GRADE2(
GRADE_CODE NUMBER PRIMARY KEY,
GRADE_NAME VARCHAR2(30) NOT NULL
);
INSERT INTO USER_GRADE2 VALUES (10, '일반회원');
INSERT INTO USER_GRADE2 VALUES (20, '우수회원');
INSERT INTO USER_GRADE2 VALUES (30, '특별회원');
-- ON DELETE SET NULL 삭제 옵션이 적용된 테이블 생성
CREATE TABLE USER_USED_FK2(
USER_NO NUMBER PRIMARY KEY,
USER_ID VARCHAR2(20) UNIQUE,
USER_PWD VARCHAR2(30) NOT NULL,
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50),
GRADE_CODE NUMBER CONSTRAINT GRADE_CODE_FK2 REFERENCES USER_GRADE2 ON DELETE SET NULL
--> 삭제 옵션 추가
);
--샘플 데이터 삽입
INSERT INTO USER_USED_FK2
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr', 10);
INSERT INTO USER_USED_FK2
VALUES(2, 'user02', 'pass02', '이순신', '남', '010-5678-9012', 'lee123@kh.or.kr', 10);
INSERT INTO USER_USED_FK2
VALUES(3, 'user03', 'pass03', '유관순', '여', '010-9999-3131', 'yoo123@kh.or.kr', 30);
INSERT INTO USER_USED_FK2
VALUES(4, 'user04', 'pass04', '안중근', '남', '010-2222-1111', 'ahn123@kh.or.kr', null);
COMMIT;
SELECT * FROM USER_GRADE2;
SELECT * FROM USER_USED_FK2;
-- 부모 테이블인 USER_GRADE2에서 GRADE_CODE=10 삭제
--> ON DELETE SET NULL이 설정되어 있어 오류 없이 삭제됨
DELETE FROM USER_GRADE2
WHERE GRADE_CODE = 10;
SELECT * FROM USER_GRADE2; -- 부모 테이블 삭제 확인(10 없음)
SELECT * FROM USER_USED_FK2; -- 자식 테이블 NULL로 변환 확인
-- 3) ON DELTET CASCADE: 부모키 삭제 시 자식키도 함께 삭제됨
-- 부모키 삭제 시 값을 사용하는 자식 테이블의 컬럼에 해당하는 행위 삭제됨
CREATE TABLE USER_GRADE3(
GRADE_CODE NUMBER PRIMARY KEY,
GRADE_NAME VARCHAR2(30) NOT NULL
);
INSERT INTO USER_GRADE3 VALUES (10, '일반회원');
INSERT INTO USER_GRADE3 VALUES (20, '우수회원');
INSERT INTO USER_GRADE3 VALUES (30, '특별회원');
-- ON DELETE CASCADE 삭제 옵션이 적용된 테이블 생성
CREATE TABLE USER_USED_FK3(
USER_NO NUMBER PRIMARY KEY,
USER_ID VARCHAR2(20) UNIQUE,
USER_PWD VARCHAR2(30) NOT NULL,
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10),
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50),
GRADE_CODE NUMBER ,
CONSTRAINT GRADE_CODE_FK3 FOREIGN KEY(GRADE_CODE) REFERENCES USER_GRADE3(GRADE_CODE) ON DELETE CASCADE
);
--샘플 데이터 삽입
INSERT INTO USER_USED_FK3
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr', 10);
INSERT INTO USER_USED_FK3
VALUES(2, 'user02', 'pass02', '이순신', '남', '010-5678-9012', 'lee123@kh.or.kr', 10);
INSERT INTO USER_USED_FK3
VALUES(3, 'user03', 'pass03', '유관순', '여', '010-9999-3131', 'yoo123@kh.or.kr', 30);
INSERT INTO USER_USED_FK3
VALUES(4, 'user04', 'pass04', '안중근', '남', '010-2222-1111', 'ahn123@kh.or.kr', null);
COMMIT;
SELECT * FROM USER_GRADE3;
SELECT * FROM USER_USED_FK3;
-- 부모 테이블인 USER_GRADE3에서 GRADE_CODE = 10 삭제
DELETE FROM USER_GRADE3
WHERE GRADE_CODE = 10;
SELECT * FROM USER_GRADE3; -- 부모 행 삭제 확인(10 없어짐)
SELECT * FROM USER_USED_FK3; -- 10을 참조하던 자식 행 삭제 확인(종속 관계의 행이 모두 삭제되었다.)
-- ON DELETE CASCADE 옵션으로 인해 참조키를 사용한 행이 삭제됨을 확인
--------------------------------------------------------------------------------
-- 5. CHECK 제약조건: 컬럼에 기록되는 값에 조건 설정을 할 수 있음
-- CHECK (컬럼명 비교연산자 비교값)
-- 주의: 비교값은 리터럴만 사용할 수 있음, 변하는 값이나 함수 사용 못함
CREATE TABLE USER_USED_CHECK(
USER_NO NUMBER PRIMARY KEY,
USER_ID VARCHAR2(20) UNIQUE,
USER_PWD VARCHAR2(30) NOT NULL,
USER_NAME VARCHAR2(30),
GENDER VARCHAR2(10) CONSTRAINT GENDER_CHECK CHECK(GENDER IN ('남','여')) ,
PHONE VARCHAR2(30),
EMAIL VARCHAR2(50)
);
INSERT INTO USER_USED_CHECK
VALUES(1, 'user01', 'pass01', '홍길동', '남', '010-1234-5678', 'hong123@kh.or.kr');
INSERT INTO USER_USED_CHECK
VALUES(2, 'user02', 'pass02', '홍길동', '남자', '010-1234-5678', 'hong123@kh.or.kr');
-- GENDER 컬럼에 CHECK 제약조건으로 '남' 또는 '여'만 기록이 가능한데,
-- '남자'라는 조건 이외의 값이 들어와서 오류 발생
-- ORA-02290: 체크 제약조건(KHJ.GENDER_CHECK)이 위배되었습니다
-- CHECK 제약조건은 범위로도 설정 가능
--------------------------------------------------------------------------------
-- [연습 문제]
-- 회원가입용 테이블 생성(USER_TEST)
-- 컬럼명 : USER_NO(회원번호) - 기본키(PK_USER_TEST),
-- USER_ID(회원아이디) - 중복금지(UK_USER_ID),
-- USER_PWD(회원비밀번호) - NULL값 허용안함(NN_USER_PWD),
-- PNO(주민등록번호) - 중복금지(UK_PNO), NULL 허용안함(NN_PNO),
-- GENDER(성별) - '남' 혹은 '여'로 입력(CK_GENDER),
-- PHONE(연락처),
-- ADDRESS(주소),
-- STATUS(탈퇴여부) - NOT NULL(NN_STATUS), 'Y' 혹은 'N'으로 입력(CK_STATUS)
-- 각 컬럼의 제약조건에 이름 부여할 것
CREATE TABLE USER_TEST(
USER_NO NUMBER CONSTRAINT PK_USER_TEST PRIMARY KEY,
USER_ID VARCHAR2(20) CONSTRAINT UK_USER_ID UNIQUE,
USER_PWD VARCHAR2(20) CONSTRAINT NN_USER_PWD NOT NULL ,
PNO VARCHAR2(30) CONSTRAINT NK_PNO NOT NULL,-- 연달아 가능한데 컴마 찍지 않기
GENDER VARCHAR2(3) CONSTRAINT CK_GENDER CHECK(GENDER IN('남','여')),
PHONE VARCHAR2(20),
ADDRESS VARCHAR2(100),
STATUS VARCHAR2(3) DEFAULT 'N' CONSTRAINT NN_STATUS NOT NULL,
CONSTRAINT CK_STATUS CHECK(STATUS IN ('Y','N')),
CONSTRAINT UK_PNO UNIQUE(PNO)
);
DROP TABLE USER_TEST;
COMMENT ON COLUMN USER_TEST.USER_NO IS '회원 번호';
COMMENT ON COLUMN USER_TEST.USER_ID IS '회원 아이디';
COMMENT ON COLUMN USER_TEST.USER_PWD IS '회원 비밀번호';
COMMENT ON COLUMN USER_TEST.PNO IS '주민등록번호';
COMMENT ON COLUMN USER_TEST.GENDER IS '성별';
COMMENT ON COLUMN USER_TEST.PHONE IS '연락처';
COMMENT ON COLUMN USER_TEST.ADDRESS IS '주소';
COMMENT ON COLUMN USER_TEST.STATUS IS '탈퇴 여부';
INSERT INTO USER_TEST
VALUES(1,'USER01','PASS01','880122-1234567','남',
'010-1111-9999','서울시 강남구 역삼동', 'N');
-- 값을 비워놓으면 NULL이나 DEFAULT값 들어감
INSERT INTO USER_TEST
VALUES (2, 'user02', 'pass02', '890222-2234567', '여', '010-2222-9999', '서울시 강남구 삼성동', 'N');
INSERT INTO USER_TEST
VALUES (3, 'user03', 'pass03', '900322-2234567', '여', '010-3333-9999', '서울시 강남구 청담동', 'Y');
INSERT INTO USER_TEST
VALUES (4, 'user04', 'pass04', '910422-1234567', '남', '010-4444-9999', '서울시 강남구 도곡동', 'N');
INSERT INTO USER_TEST
VALUES (5, 'user05', 'pass05', '920522-2234567', '여', '010-5555-9999', '서울시 강남구 대치동', 'N');
-- 테이블 확인
SELECT * FROM USER_TEST;
-- 테이블 주석 확인
SELECT * FROM USER_COL_COMMENTS
WHERE TABLE_NAME = 'USER_TEST';
-- 테이블 제약조건 확인
SELECT * FROM USER_CONSTRAINTS C1
JOIN USER_CONS_COLUMNS C2 USING(CONSTRAINT_NAME)
WHERE C1.TABLE_NAME = 'USER_TEST';
SELECT * FROM USER_CONS_COLUMNS;
--------------------------------------------------------------------------------
-- 8. SUBQUERY를 이용한 테이블 생성
-- 컬럼명, 데이터 타입, 값이 복사되고, 제약조건은 NOT NULL만 복사됨
-- (CHECK 안에 NOT NULL이 포함되어 있다 -> 그래서 제약조건 검색하면 NOT NULL도 CHECK로 표시됨
-- 하지만, CHECK(GENDER IN ('남','녀')) 이런 CHECK 제약조건은 복사가 안 됨
-- 1) 테이블 전체 복사
CREATE TABLE EMPLOYEE_COPY
AS SELECT * FROM EMPLOYEE;
SELECT * FROM EMPLOYEE_COPY;
-- 2) JOIN 후 원하는 컬럼만 테이블로 복사
CREATE TABLE EMPLOYEE_COPY2
AS SELECT EMP_ID, EMP_NAME, DEPT_TITLE, JOB_NAME
FROM EMPLOYEE
LEFT JOIN DEPARTMENT ON(DEPT_CODE = DEPT_ID)
JOIN JOB USING(JOB_CODE);
DROP TABLE EMPLOYEE_COPY2;
SELECT * FROM EMPLOYEE_COPY2;
-- 3) 테이블 형태(컬럼명, 데이터 타입)만 복사 (데이터 복사X)
CREATE TABLE EMPLOYEE_COPY3
AS SELECT * FROM EMPLOYEE
WHERE 1 = 0; -- 일부러 FALSE 조건 만들어서 해당하는 데이터 없게
SELECT * FROM EMPLOYEE_COPY3;
-------------------------------------------------------------------------------------
-- 9. 제약조건 추가
-- ALTER TABLE 테이블명 ADD [CONSTRAINT 제약조건명] PRIMARY KEY(컬럼명)
-- ALTER TABLE 테이블명 ADD [CONSTRAINT 제약조건명]
-- FOREIGN KEY(컬럼명) REFERENCES 참조 테이블명(참조컬럼명)
--> 참조 테이블의 PK를 기본키를 FK로 사용하는 경우 참조컬럼명 생략 가능
-- ALTER TABLE 테이블명 ADD [CONSTRAINT 제약조건명] UNIQUE(컬럼명)
-- ALTER TABLE 테이블명 ADD [CONSTRAINT 제약조건명] CHECK(컬럼명 비교연산자 비교값)
-- ALTER TABLE 테이블명 MODIFY 컬럼명 NOT NULL;
-- 테이블 제약조건 확인
SELECT * FROM USER_CONSTRAINTS C1
JOIN USER_CONS_COLUMNS C2 USING(CONSTRAINT_NAME)
WHERE C1.TABLE_NAME = 'EMPLOYEE_COPY';
-- NOT NULL 제약조건만 복사된 EMPLOYEE_COPY 테이블에
-- EMP_ID 컬럼에 PRIMARY KEY 제약조건 추가
ALTER TABLE EMPLOYEE_COPY ADD
CONSTRAINT PK_EMP_COPY PRIMARY KEY(EMP_ID);
-- * 수업시간에 활용하던 테이블에는 FK 제약조건 없는 상태이므로 추가!!
-- EMPLOYEE테이블의 DEPT_CODE에 외래키 제약조건 추가
-- 참조 테이블은 DEPARTMENT, 참조 컬럼은 DEPARTMENT의 기본키
ALTER TABLE DEPARTMENT ADD
CONSTRAINT FK_DEPT_ID FOREIGN KEY(DEPT_ID) REFERENCES DEPARTMENT;
-- 컬럼명 생략 시 DEPARTMENT PK 컬럼과 연결
-- EMPLOYEE테이블의 JOB_CODE 외래키 제약조건 추가
-- 참조 테이블은 JOB, 참조 컬럼은 JOB의 기본키
ALTER TABLE EMPLOYEE ADD
FOREIGN KEY(JOB_CODE) REFERENCES JOB;
-- EMPLOYEE테이블의 SAL_LEVEL 외래키 제약조건 추가
-- 참조 테이블은 SAL_GRADE, 참조 컬럼은 SAL_GRADE의 기본키
ALTER TABLE EMPLOYEE ADD
FOREIGN KEY(SAL_LEVEL) REFERENCES SAL_GRADE;
-- DEPARTMENT테이블의 LOCATION_ID에 외래키 제약조건 추가
-- 참조 테이블은 LOCATION, 참조 컬럼은 LOCATION의 기본키
ALTER TABLE DEPARTMENT ADD
FOREIGN KEY(LOCATION_ID) REFERENCES LOCATION;
-- LOCATION테이블의 NATIONAL_CODE에 외래키 제약조건 추가
-- 참조 테이블은 NATIONAL, 참조 컬럼은 NATIONAL의 기본키
ALTER TABLE LOCATION ADD
FOREIGN KEY(NATIONAL_CODE) REFERENCES NATIONAL;