GitHub

https://github.com/Backcoder-June

BackCoder 기록 그리고 숙달

Back to the DataBase

Foreign Key / CASCADE / 그리고 Constraint 제약조건들.

Backcoder 2022. 7. 15. 20:01


- DB 에서 테이블을 생성할 때, 여러 특성, 제약조건을 걸 수 있다. ( 걸어야 한다. )
몇개 없다. 간단하게 보고, 그 중 헤깔리기 쉬운 FOREIGN KEY 사용법에 익숙해 지자.

< 특성 / 제약조건 Constraint >
1. not null => null 금지
( 아이디나 비밀번호, 주민번호 같은 data 들 )


2. unique => 중복값 금지 ( unique key UK 라고 표현 )
( 아이디, 주민번호 둘 다 중복되면 안되는 data 들)


3. primary key => not null + unique 특성 ( PK )
+ Auto_increment 자동증가 특성과 함께 사용한다.


예시 : id varchar(10) primary key auto_increment,


( => auto_increment 를 설정해두면 자동으로 pk값을 1씩 증가시키기 때문에
insert 할때, 안적어도 되긴하는데,
insert into Table ( (pk생략), pw, name, ... ) values ( )
이렇게 pk 빼고의 양식이라고 알려주고 넣어야함 )

4. check => 사용자정의로 양식 제한걸기


email varchar(30) check ( 해당칼럼 like '%@%' );
PW int check ( Length(PW) <= 4 );
( 현 시점, MySQL은 int 에 길이 제약이 안되는 상황이니 이런식으로 걸어둘 수 있겠다. )


5. default => 기본값 할당


hire_date datetime default now(),


=> insert 할때 default 키워드 적어줘야함

insert into Table values( 1, 'june', default, 2 );

=> default 말고 값 주고싶으면, 직접 적어주면 overriding 됨



6. Foreign Key => 다른 테이블의 다른컬럼 존재값 저장 ( 공유컬럼, 연결고리 )

create Table ~ ( ~
writer varchar(30) not null;
Foreign Key( writer ) references member ( id ) ) ;

Foreign key( 자식 컬럼명 ) References 부모테이블 ( 참조컬럼명 );

=> (부모)member테이블의 (참조컬럼)id를 참조해서 그 값만 사용할 수있는
foreign key로 (자식테이블의) writer 컬럼을 지정하겠다.
( references - 참조 => 이 값만을 사용할 수 있다. => 무결성 )

( PK와는 다르게, 따로 선언해줘야 한다. )


< foreign key 사용 Join 예시 >

- 먼저, Join 을 할때는, 공유하는 컬럼이 있어야 가능하다.
공유하는 컬럼이 있다면, 사실 foreign key 를 설정하지 않아도
Join 해서 데이터를 사용은 가능하다.

- 그럼 왜 Foreign 키를 굳이 쓰는가?

어려운 말로는 '참조 무결성의 원칙' 을 지키기 위해서다.

즉, Foreign 키명시적으로

" 이 공유컬럼을 foreign key 로 쓸게요! "

라고 해두면, 거기엔( 자식 foreign key 컬럼) 참조하는 테이블 컬럼( 부모테이블 컬럼) 의 데이터 TYPE 에 해당하는,
그 양식에 맞춰서만 데이터를 집어 넣을 수 있기 때문에,
Join 을 하는데 있어 무결성을 보장해 준다는 것이다.

ex ) 부모 테이블의 id 컬럼을 참조해서 foreign key 를 설정했다.
id컬럼은 int 로 4글자만 올 수 있다.
그럼 foreign key 에도 같은 조건인 int 4 글자만 넣을 수 있다. ( 안지키면 오류가 난다! )

스스로 약속을 걸어둬서 안전성을 높이는 것.

( foreign key를 걸어두면 속도 등 성능이 더 좋아진다? 하기에는 있어서는 논란이 있어 보인다. )
( 어쨋든 무결성 원칙 하나만으로도, 대부분 foreign key 는 사용하는 추세이다 )


그럼 이제 foreign key 를 사용해 무결성을 보장하며 Join을 시켜보자.

create table ~(
writer varchar(30) not null;
foreign key(writer) references member(id) );
//foreign 키 지정해두고

name은 student테이블 / title contents는 memo테이블 에 있는 상황.

select name, title, contents
from student s
INNER JOIN memo m
ON s.id = m.writer ;

=> 원래 join 하듯이 하면 되는데,
foreign 키로 명시적으로 지정해둔 컬럼
연결하고자하는 테이블의 컬럼이 같을 때를 조건으로 주고 join 하면 된다.

( foreign 키는 사실 상, 처음 테이블 생성할 때 지정해둬야지,
Data 들어가고 나서는 여러 문제들이 발생할 수 있어 사실상 힘들다. )



< Foreign key 가 설정되있으면, (부모)Data를 함부로 delete 를 하지 못한다. > (참조상태)

delete from 부모테이블
where name = 'june'; (X)

=> ( 자식 ) 테이블에 Foreign key 로 연결된 ( 부모 )데이터가 남아있어서 삭제할 수 없다.
( error : Cannot delete or update a parent row: a foreign key constraint fails )

=> 부모데이터 삭제시 자식테이블에있는 부모데이터도 같이 삭제하게끔
설정을 추가해야한다.

1. 기존 foreign key 삭제 ( 먼저 foreign key 연결고리를 끊어야 한다. )
ALTER table 자식테이블 DROP FOREIGN KEY 자식테이블_ibfk_1;
( 뒤에 번호는 fk 설정 회수에 따라 올라간다. 기본 1 )

이제 foreign key 연결은끊었고,

2. 다시 foregin key를 설정하면서
+ 특성으로 부모삭제시 자식데이터 같이 삭제하는 설정을 추가해준다.

ALTER table 자식테이블 ADD CONSTRAINT FOREIGN KEY(자식컬럼) References 부모테이블(참조컬럼);
ON DELETE CASCADE ON UPDATE CASCADE;

=> foreign 키 자식컬럼에 부모테이블 컬럼참조해서 지정할껀데,
할때 (ON) DELETE 할때나 UPDATE 할때 CASCADE ( 폭포, 즉 부모가 하면 자식도 하게끔 ) 방식으로 해줘!

=> 이렇게 foreign key 특성을 설정을 해두면,
자식테이블에 foreign key로 연결된 부모 데이터가 남아있더라도

delete from 부모테이블
where name = 'june'; ( O )

부모테이블에서 데이터를 삭제하면, 자식테이블에 남아있는 부모데이터까지
CASCADE 해서 같이 삭제해준다. ( UPDATE 도 마찬가지 )

ex) 부모 테이블에서 june 데이터를 삭제하면 => june 이 작성한 자식테이블에 있는 게시글 data 들도 같이 삭제


=> 애초에 FOREIGN KEY 를 설정 할때, CASCADE 기능이 필요한 지 생각해두고
( 게시판 글 같은 경우, 사용자가 탈퇴하면 사용자가 작성한 글 들도 같이 삭제할 것인지 )
처음 설계할 때 설정을 꼼꼼히 해두어야 한다! ( 나중에는 고치기가 상당히 까다롭다 )



< 제약 조건 추가 / 삭제 / 수정 => ALTER >

- 이미 데이터가 저장이 되고 나서는 제약조건을 추가해봤자
제약 조건을 어긴 데이터들은 적용이 잘 안되고 문제가 생길 수 있다.
( 데이터 다 지울 수 있을 때 사용 )

delete from memo; <= 먼저 데이터를 다 날리고

alter table memo add constraint foreign key(writer) references member(id);
add constraint unique(컬럼명)
add constraint primary key (컬럼명)
add constraint check ( )

이런식으로 ALTER + ADD CONSTRAINT 제약조건

해주면 되지만,

( 사실상 사용 할 일이 많이 없어야 겠다. )



Foreign Key
JAVADB 연동시, JAVA 에서도 직접적으로 손에 닿고, 만져지는 조건인 만큼
( Java 에서도 CACADE 를 설정하고, Many to One / One to Many 관계를 설정하는 등
테이블 끼리의 Join 에 깊게 관여한다.) 확실하게 개념을 잡고 있어야 겠다.