참조키 (외래키, FOREIGN KEY)
- 테이블 간의 데이터의 일관성을 보장하기 위한 제약조건이다.
- 한 테이블의 PRIMARY KEY나 UNIQUE 컬럼을 다른 테이블에 추가하여 두 테이블 간 연결을 설정한다.
- 부모 테이블이 먼저 생성된 후 자식 테이블(FOREIGN KEY를 포함하는 테이블)이 생성되어야 한다.
예제를 통해 알아보자.
-- std : 부모 테이블
CREATE TABLE std (
hak VARCHAR2(30) PRIMARY KEY,
name VARCHAR2(30) NOT NULL,
email VARCHAR2(50) NOT NULL,
tel VARCHAR2(30) NOT NULL
);
-- std_score : 자식 테이블
-- 부모의 PRIMARY KEY 또는 UNIQUE 만 참조 가능
CREATE TABLE std_score(
num NUMBER PRIMARY KEY,
hak VARCHAR2(30) NOT NULL,
gubun NUMBER(1) NOT NULL,
java NUMBER(3) NOT NULL,
oracle NUMBER(3) NOT NULL,
CONSTRAINT fk_stdscore_hak FOREIGN KEY ( hak )
REFERENCES std(hak)
);
SELECT * FROM USER_CONSTRAINTS WHERE table_name = 'STD';
SELECT * FROM USER_CONSTRAINTS WHERE table_name = 'STD_SCORE';
-- P : 기본키, R : 참조키
SELECT * FROM USER_CONS_COLUMNS WHERE table_name = 'STD';
SELECT * FROM USER_CONS_COLUMNS WHERE table_name = 'STD_SCORE';
CREATE TABLE 문에서 FOREIGN KEY를 추가할 때는 FOREIGN KEY (컬럼) REFERENCES 참조하는테이블(참조하는컬럼) 을 통해 추가한다.
기본키는 CONSTRAINT TYPE 이 P로 되어있고 참조키는 R로 되어있다.
데이터를 추가해보자.
INSERT INTO std_score(num, hak, gubun, java, oracle) VALUES (1, '11', 1, 100, 90);
-- 에러 ORA-02291 : 부모 테이블에 존재하지 않는 hak은 추가 불가
INSERT INTO std(hak, name, email, tel) VALUES ('11', 'aa', 'aa', '11');
INSERT INTO std(hak, name, email, tel) VALUES ('22', 'bb', 'bb', '22');
INSERT INTO std(hak, name, email, tel) VALUES ('33', 'cc', 'cc', '33');
INSERT INTO std_score(num, hak, gubun, java, oracle) VALUES (1, '11', 1, 100, 90);
INSERT INTO std_score(num, hak, gubun, java, oracle) VALUES (2, '11', 2, 90, 90);
INSERT INTO std_score(num, hak, gubun, java, oracle) VALUES (3, '33', 1, 90, 90);
COMMIT;
SELECT * FROM std;
SELECT * FROM std_score;
부모테이블에 아직 아무데이터도 있지 않은 상태이다. 이 상태에서 자식테이블에 값을 추가하면 에러(ORA-02291)가 발생한다.
참조하는 키가 먼저 부모테이블에 존재해야 자식테이블에 값도 추가할 수 있다.
먼저 부모 테이블에 데이터를 입력하고 자식테이블에도 입력을 하면 잘 들어가는 것을 확인할 수 있다.
입력된 데이터의 값을 수정하거나 삭제해보자.
DELETE FROM std WHERE hak = '11';
-- 에러 ORA-02292 : 참조하는 레코드가 있음.
UPDATE std SET hak = '13' WHERE hak = '11';
-- 에러 ORA-02292 : 참조하는 레코드가 있음
UPDATE std SET hak = '23' WHERE hak = '22';
-- 가능 : 참조하는 레코드가 없음
SELECT * FROM std;
DELETE FROM std WHERE hak = '23';
-- 가능
부모테이블에 있는 PRIMARY KEY인 HAK을 바꿔보려 했으나 이 값을 참조키로 자식테이블에서 데이터를 추가했기 때문에 오류가 발생한다.(ORA-02292) 하지만 HAK 22의 경우 이 값으로 하여금 자식 테이블이 가지고 있는 값이 아무 것도 없기 때문에 23으로 변경할 수 있었다. 또 삭제도 가능했다.
자식이 부모테이블에있는 컬럼을 참조키로 가지고 있는 경우, 부모 테이블은 여태까지 했던 방식으로는 불가하다.
DROP TABLE std PURGE;
-- 에러 ORA-02449 : 참조하는 테이블이 있으면 삭제 불가
-- 모든 자식 테이블을 먼저 삭제하고 삭제해야 함
에러 (ORA - 02449)가 발생한다.
강제로 삭제하는 방법이 존재한다. 참조키를 삭제해 부와 자의 관계를 없앤다.
-- 강제로 삭제. 참조키가 삭제 됨(부와 자의 관계가 없어짐)
DROP TABLE std CASCADE CONSTRAINTS PURGE;
SELECT * FROM tab;
SELECT * FROM USER_CONSTRAINTS WHERE table_name = 'STD_SCORE';
-- R(참조키)이 제거됨
DROP TABLE std_score PURGE;
명령어
DROP TABLE std CASCADE CONSTRAINTS PURGE;
통해서 부모테이블을 강제로 삭제했다. 그 후 테이블 제약조건을 확인해보니 원래 HAK은 CONSTRAINT_TYPE 이 FOREIGN KEY 였기 때문에 F 였으나 이제는 NOT NULL의 CHECK조건을 가지고 있으므로 C로 바뀌어있는 것을 확인할 수 있다. 참조키를 가지고 있지 않기 때문에 평소 했던 방법으로 테이블을 삭제할 수 있다.
DROP TABLE std_score PURGE;
참조하는 컬럼과 참조당하는 컬럼은 타입과 크기가 같아야한다. 하지만 컬럼명은 다를 수 있다.
예시를 통해 알아보자.
-- std : 부모 테이블
CREATE TABLE std (
hak VARCHAR2(30) PRIMARY KEY,
name VARCHAR2(30) NOT NULL,
email VARCHAR2(50) NOT NULL,
tel VARCHAR2(30) NOT NULL
);
-- std_score : 자식 테이블
CREATE TABLE std_score(
num NUMBER PRIMARY KEY,
shak VARCHAR2(30),
gubun NUMBER(1) NOT NULL,
java NUMBER(3) NOT NULL,
oracle NUMBER(3) NOT NULL,
FOREIGN KEY ( shak )
REFERENCES std(hak)
);
SELECT * FROM USER_CONSTRAINTS WHERE table_name = 'STD';
SELECT * FROM USER_CONSTRAINTS WHERE table_name = 'STD_SCORE';
SELECT * FROM USER_CONS_COLUMNS WHERE table_name = 'STD';
SELECT * FROM USER_CONS_COLUMNS WHERE table_name = 'STD_SCORE';
테이블에 데이터를 넣어보자.
INSERT INTO std_score(num, shak, gubun, java, oracle) VALUES (1, NULL , 1, 100, 90);
-- 가능. 부모에 존재하지 않아도 참조키가 NULL이 가능하므로 NULL은 추가 가능
INSERT INTO std_score(num, shak, gubun, java, oracle) VALUES (2, '11', 1, 80, 90);
-- 에러 ORA-02291 : 부모의 hak에 11이 없음.
자식테이블에 외래키에 NOT NULL 조건을 붙이지 않았으므로 NULL이 가능하다.
하지만 자식테이블의 참조키에 NULL 이외의 값으로는 데이터를 추가할 수 없다. 부모테이블에 값이 있어야 추가가 가능하다.
'쌍용강북교육센터 > 8월' 카테고리의 다른 글
0812_Oracle : 데이터 사전 확인 (0) | 2021.08.12 |
---|---|
0811_Oracle : 식별관계/비식별관계, ERD, 참조키 활성화/비활성화 (2) | 2021.08.11 |
0811_Oracle : DEFAULT와 CHECK 제약조건 (1) | 2021.08.11 |
0811_Oracle : UNIQUE 제약조건과 NOT NULL 제약조건 (1) | 2021.08.11 |
0811_Oracle : 기본키 PRIMARY KEY와 제약조건 (2) (1) | 2021.08.11 |