Infra & Security Eng/Database Engineering
[Oracle] 제약 조건(UK, CHECK, NOT NULL) 완벽 정리와 실습
엔지니어 E
2026. 2. 10. 12:23
반응형

1. UK 개념 (Unique Key, 고유 키)
| 해당 컬럼에 중복된 값이 들어올 수 없도록 보장함 (예시. 이메일, 주빈번호 등) |
2. NOT NULL 개념 (필수 입력 제약)
| 해당 컬럼에 NULL(빈 값)이 들어오는 것을 방지함. 즉, 데이터를 입력할 때 이 컬럼은 무조건 값을 채워야 함을 의미함 |
3. 상세 비교 테이블
| 구분 | NOT NULL | UNIQUE (UK) |
| 목적 | 빈 값 방지 (필수값 설정) | 중복 값 방지 (유일성 보장) |
| NULL 허용 | 불가능 | 가능 |
| 인덱스 생성 | 생성 안 됨 | 자동으로 고유 인덱스 생성 |
| 정의 위치 | 컬럼 레벨만 가능 | 컬럼 & 테이블 레벨 모두 가능 |
4. UK(Unique Key), NOT NULL 설정과 예제
| 모든 칸(컬럼)을 다 만든 뒤에, 맨 밑에서 한꺼번에 규칙을 정하는 방법 CREATE TABLE 테이블 ( ..... CONSTRAINT 제약_조건 UNIQUE (컬럼)); 예제 CREATE TABLE member ( id VARCHAR2(10) PRIMARY KEY, -- 이 칸의 이름은 ID 라고 부르겠다, 최대 10글자 까지 문자를 넣고, PRIMARY KEY(제약 조건) 은 비어있으면 안 되고(NOT NULL), 중복되어도 안 된다(UNIQUE) ID ---------- USER01 name VARCHAR2(20) CONSTRAINT mem_name_nn NOT NULL, ---> 이름은 비어있으면 안 됨(컬럼 레벨) email VARCHAR2(50) CONSTRAINT mem_email_uk UNIQUE, ---> 메일은 중복되면 안됨 (컬럼 레벨) phone VARCHAR2(15), CONSTRAINT mem_phone_uk UNIQUE (phone) ---> 전화번호 중복 방지(테이블 레벨 방식) ); * 컬럼 레벨: 컬럼을 만드는 그 줄에 제약 조건을 바로 적는 방식 * 테이블 레벨: 모든 컬럼을 다 나열한 뒤, 맨 마지막 줄에 제약 조건을 따로 모아서 적는 방식 칸(컬럼)을 만들면서 그 자리에서 즉시 규칙을 정하는 방법 CREATE TABLE 테이블 ( 컬럼 데이터_타입 CONSTRAINT 제약_조건 NOT NULL, ......; 예제 CREATE TABLE member ( userid VARCHAR2(20) CONSTRAINT mem_id_nn NOT NULL, -- 아이디 (필수 입력) name VARCHAR2(30) CONSTRAINT mem_nm_nn NOT NULL, -- 이름 (필수 입력) age NUMBER -- 나이 (선택 사항, 빈값 허용) ); |
5. CHECK 개념
| 데이터가 입력될 때, 그 값 자체가 미리 정해둔 조건에 맞는지 검사하는 제약조건 단순히 중복이나 빈 값을 막는 것을 넘어, 데이터의 내용이 논리적으로 올바른지 확인 |
6. CHECK 설정과 예제
| CREATE TABLE 테이블 ( ..... CONSTRAINT 제약_조건 CHECK (조건)); 예제 CREATE TABLE goods ( ---> goods 라는 이름의 데이터 저장소를 생성 gno VARCHAR2(8), ---> 제품 번호를 저장, 최대 8글자의 문자(숫자 포함)를 허용 gname VARCHAR2(50), ---> 제품 이름을 저장, 최대 50글자의 문자를 허용 pri NUMBER(10, 2), ---> 제품 가격을 저장, 소수점 초함 총 10자리(소수점 2자리 포함) 숫자를 허용 -- [CHECK 제약조건] -- 이름: goods_chk_pri -- 내용: pri(가격) 컬럼에 들어오는 숫자는 반드시 0보다 커야 함을 검사함 CONSTRAINT goods_chk_pri CHECK (pri > 0) ); |
UK, CHECK, NOT NULL을 적용한 테이블 생성
| 컬럼명 | eno(사번) | ename(이름) | gno(주민번호) | sex(성별) |
| PK/UK/NOT NULL | PK | NOT NULL | UK | |
| 참조 테이블 | ||||
| 참조 컬럼 | ||||
| CHECK | LENGTH(13) | (여, 남) | ||
| 데이터 타입 | VARCHAR2 | VARCHAR2 | ||
| 길이 | 4 | 50 | 13 | 4 |
| CREATE TABLE emp3 ( -- emp3라는 이름의 테이블(저장소)을 생성 eno VARCHAR2(4), -- 사번(eno)은 최대 4글자까지 문자로 저장 ename VARCHAR2(50) CONSTRAINT emp3_ename_nu NOT NULL, -- 이름(ename)은 최대 50글자이며, 비워둘 수 없음 (NOT NULL). gno VARCHAR2(13), -- 주민번호(gno)는 13글자 문자로 저장함 sex VARCHAR2(4), -- 성별(sex)은 최대 4바이트(한글 1~2자)까지 문자로 저장함 CONSTRAINT emp3_eno_pk PRIMARY KEY (eno), -- 사번(eno)을 중복이나 빈값 없이 유일한 열쇠로 지정함 CONSTRAINT emp3_gno_uk UNIQUE (gno), -- 주민번호(gno)는 다른 사람과 겹치지 않게 유일해야 함 CONSTRAINT emp3_gno_ch CHECK (LENGTH(gno) = 13), -- 주민번호(gno)는 반드시 정확히 13글자여야만 저장됨 * CHECK(LENGTH(gno)=13: gno에 데이터를 넣을때마다 매번 글자 수를 확인 해서 13글자가 아니면 입구컷 시켜라 라는 뜻 CONSTRAINT emp3_sex_ch CHECK (sex IN ('여', '남')) -- 성별(sex)은 '여' 또는 '남'이라는 글자만 입력 가능함 * CHECK (sex IN ('여', '남'): sex 컬럼에 들어올 값이 '여' 아니면 '남' 둘 중 하나일때만 입장을 허용해라 라는 뜻 ); emp3_eno_pk 풀이 emp3: 테이블 이름 eno: 컬럼 이름 pk: 제약 조건의 종류(Primary Key) 주민번호: 주 식별자로 가능하지만 너무 길어서 사용하지 않음 * 주 식별자는 길이가 짧아야 함 |
실습하기
| 아래 도표를 보고 테이블을 생성한다. - 테이블 명에 한글을 허용 한다 |



| 논리프로세스 1단계 - 빌려줄 데이터(기준)를 먼저 만든다 제품 테이블과 판매전표 테이블을 먼저 만들어야 한다 이유: 전표 상세 테이블은 어떤 물건(제품)을 어떤 영수증(판매전표)에 담을지 기록하는 곳이다. 물건 정보와 영수증 번호가 세상에 먼저 존재해야 그것을 가져다 쓸 수 있다 2단계 - 빌려 쓰는 데이터(상세)를 나중에 만든다 전표 상세 테이블을 마지막에 만든다 이유: 이 테이블은 FOREIGN KEY(외래키) 를 통해 제품의 번호와 판매전표의 번호를 빌려와서 사용한다. 만약 기준이 되는 테이블들이 없다면, 컴퓨터는 어디서 번호를 가져오는거야라며 에러를 가져오게 된다 3단계 - 삭제할 때는 만든 순서의 반대로 한다 삭제할 때는 전표상세부터 지운다 이유: 엄마(기준 테이블) 를 지우려는데 자식(상세 테이블이) 이 엄마 다리를 붙잡고(참조) 있으면 지울 수 없기 때문이다. 그래서 붙잡고 있는 자식부터 지우고 엄마(부모)를 지웅는 순서가 안전하다 |
| 실습하기 SET LINESIZE 150; -- 화면 가로 길이를 150자로 넓혀서 표가 깨지지 않게 함 SET PAGESIZE 50; -- 세로 50줄마다 제목이 나오게 설정함 1. 기존 테이블 삭제 (자식 테이블인 '전표상세'부터 지워야 오류가 안 남) DROP TABLE "전표상세" CASCADE CONSTRAINTS; -- 판매전표와 제품을 참고하는 상세 테이블 먼저 삭제 DROP TABLE "판매전표" CASCADE CONSTRAINTS; -- 전표의 기본 정보를 담은 테이블 삭제 DROP TABLE "제품" CASCADE CONSTRAINTS; -- 제품 목록이 담긴 테이블 삭제 2. [제품] 테이블: 팔 물건들의 정보를 모아둔 곳 CREATE TABLE "제품" ( "제품번호" VARCHAR2(12), -- 제품의 고유 번호 (최대 12자) "제품명" VARCHAR2(100), -- 제품의 이름 (최대 100자) "제품단가" NUMBER, -- 제품 1개의 가격 CONSTRAINT "제품_제품번호_PK" PRIMARY KEY ("제품번호"), -- 제품번호는 중복 안 되고 비어있으면 안 됨 CONSTRAINT "제품_제품명_UK" UNIQUE ("제품명"), -- 제품 이름도 서로 중복될 수 없음 CONSTRAINT "제품_제품단가_CK" CHECK ("제품단가" > 0) -- 제품 가격은 반드시 0보다 커야 함 ); 3. [판매전표] 테이블: 누가 언제 샀는지 큰 정보를 담는 곳 CREATE TABLE "판매전표" ( "전표번호" VARCHAR2(12), -- 영수증 번호 (최대 12자) "판매일자" DATE CONSTRAINT "판매전표_판매일자_NN" NOT NULL, -- 언제 샀는지 반드시 적어야 함 "고객명" VARCHAR2(50) CONSTRAINT "판매전표_고객명_NN" NOT NULL, -- 산 사람 이름을 반드시 적어야 함 "총액" NUMBER CONSTRAINT "판매전표_총액_NN" NOT NULL, -- 전체 금액을 반드시 적어야 함 CONSTRAINT "판매전표_전표번호_PK" PRIMARY KEY ("전표번호"), -- 전표번호는 중복 안 되고 비어있으면 안 됨 CONSTRAINT "판매전표_총액_CK" CHECK ("총액" > 0) -- 전체 금액은 반드시 0보다 커야 함 * 실수나 오류로 인해 가격이 0원(공짜)이나 마이너스(마이너스 금액)으로 입력되는 상황을 봉쇄하여 데이터의 정확성을 지키기 위해 ); 4. [전표상세] 테이블: 한 장의 영수증 안에 어떤 물건들을 몇 개 샀는지 구체적으로 적는 곳 CREATE TABLE "전표상세" ( "전표번호" VARCHAR2(12), -- 어떤 영수증에 속하는지 (판매전표 번호) "제품번호" VARCHAR2(12), -- 어떤 물건을 샀는지 (제품 번호) "수량" NUMBER CONSTRAINT "전표상세_수량_NN" NOT NULL, -- 몇 개 샀는지 반드시 적어야 함 "단가" NUMBER CONSTRAINT "전표상세_단가_NN" NOT NULL, -- 당시 가격을 반드시 적어야 함 "금액" NUMBER CONSTRAINT "전표상세_금액_NN" NOT NULL, -- (수량x단가) 금액을 반드시 적어야 함 -- 제약 조건 CONSTRAINT "전표상세_PK" PRIMARY KEY ("전표번호", "제품번호"), -- 한 영수증 안에서 같은 제품은 한 줄만 기록함 CONSTRAINT "전표상세_전표번호_FK" FOREIGN KEY ("전표번호") REFERENCES "판매전표" ("전표번호"), -- 실제 있는 영수증 번호만 써야 함 CONSTRAINT "전표상세_제품번호_FK" FOREIGN KEY ("제품번호") REFERENCES "제품" ("제품번호"), -- 실제 있는 제품 번호만 써야 함 CONSTRAINT "전표상세_금액_CK" CHECK ("금액" > 0) -- 계산된 금액은 반드시 0보다 커야 함 ); -- 테이블이 잘 만들어졌는지 설계도 확인 DESC "제품"; DESC "판매전표"; DESC "전표상세"; |