안녕하세요

프로그램 과정에서 막혔던 문제들에 대한 해결책 정리


페이지 목록

2017년 3월 15일 수요일

[MySQL] 외래키(Foreign Key) 설정 방법

Mysql에서 innodb 는 상용DB와 비슷한 기능들을 지원한다. 
물론 아직도 지원하지 않는 기능이 많지만...  그럭저럭 쓸만하다. 
다음은 그중 외래키 지원에 관한것이다. 

외래키란 A, B 라는 테이블이 있을경우 
A 테이블 Key 값을 참조하여 B 테이블에서 사용할때 B테이블의 Key를 외래키라고 한다. 
참고로 A 테이블의 참조하는 키를 참조키라고 한다. 
그러므로 A 테이블의 참조키와 B 테이블의 외래키값은 동일한 값이 들어간다. 
그외 자세한 내용은 인터넷에 많으니 찾아보시고... ^^ 

그러나 Web 쪽에서 Mysql 이 많이 사용되다 보니 거의 외래키를 사용할일이 없고.. 
웹호스팅사에서도 거의 InnoDB는 잘 지원하지 않다 보니 자주 사용되지는 않는다. 
Mysql 서버를 독자적으로 쓰거나.. 또는 업무용 프로그램의 DB로 사용한다면 
외래키 및 트랜젝션 처리를 사용하게 될것이다. 

그럼 왜 외래키를 이용할까? 
그건 데이터의 정확성 때문이라고 할수 있다. 
왜 정확해 지냐라고 묻는다면 아래의 예제를 설명하고 나서 이야기 하겠다. 

우선 다음과 같은 테이블을 만들자. 
member_info : 회원 테이블 
member_login : 회원이 로그인하면 로그인시간을 기록하는 테이블 

CREATE TABLE `member_info` ( 
    `id` VARCHAR(20) NOT NULL DEFAULT '', 
    `name` VARCHAR(16) NOT NULL DEFAULT '', 
    PRIMARY KEY(`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

CREATE TABLE `member_login` ( 
    `id` varchar(20) NOT NULL, 
    `logintime` datetime NOT NULL default '0000-00-00 00:00:00', 
    PRIMARY KEY  (`id`), 
    CONSTRAINT `fk_id` 
        FOREIGN KEY (`id`) REFERENCES `member_info` (`id`) 
            ON DELETE CASCADE 
            ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

member_info 테이블은 기본적인 테이블 만드는 방법이다. 
DDL(Create, Drop, Alter)문에 대한 설명은 여기서 하지 않겠다. 

member_login 테이블이 실제 외래키를 담고 있는 테이블이다. 
CONSTRAINT `fk_id` <== 제약조건을 건다는 말이며 그 이름을 fk_id 라고 지정했다 
FOREIGN KEY (`id`) <== 현재테이블의 필드명이 id 인것이 외래키라는것을 의미한다. 
REFERENCES `member_info` (`id`) <== member_info 테이블의 id 필드를 참조한다는 것을 의미한다. 
ON DELETE CASCADE <== 참조키가 삭제되면 외래키도 삭제한다 
ON UPDATE CASCADE <== 참조키가 업데이트 되면 외래키도 업데이트를 한다. 

현재 테스트 버젼 5.0.37에서는 지원하는 옵션은 4가지가 있다. 
CASCADE 
  참조키와 동일하게 맞춘다. 즉 참조키값이 삭제되면 해당 테이블의 동일한 레코드도 삭제되며 
  참조키값이 업데이트(예 aa => bb 로 바뀐다면)되면 외래키값도 업데이트(aa => bb 로 바뀐다)가 된다. 
RESTRICT : 참조키가 삭제되거나 업데이트 되는걸 막는다. 
SET NULL : 참조키가 삭제되거나 업데이트 되면 외래키값을 null 로만든다. 
NO ACTION : 참조키가 삭제되거나 업데이트 되어도 아무런 동작을 하지 않는다. 이 경우는 외래키의 의미가 없다고 볼수 있다. 

그럼 insert 문을 실제 데이터를 입력해 보자. 

insert into member_info values('test1','테스터1'); 
insert into member_login values('test1',now()); 

위의 sql문을 순서를 바꾸어서 실행하면 에러가 날것이다. 
회원정보 테이블(member_info)이 중심테이블이라고 한다면... member_login 테이블은 
회원정보 테이블(member_info)에 종속적이라고 할수 있다. 
즉 member_info 테이블의 id 값에 있는것이 member_login의 id값이 들어갈수 있는것이다. 
그러니.. insert 문 작성시 member_info 부터 입력해야 한다. 

현재 테이블 설정이 CASCADE 이니 조금전에 입력한 member_info의 id 값 'test1' 을 update 해보자. 

update member_info set id='test2' where id='test1'; 

이제 member_login 의 데이터를 select 해서보면 

select * from member_login 을 해보면.. 

member_login 을 업데이트를 하지 않았음에도 외래키값이 update 되어있는걸 확인할수 있을것이다. 
그럼 삭제는 어떨까? 
member_info 의 id='test2' 값을 다시 삭제하면 member_login의 row 데이터도 같이 삭제된것을 
볼수 있다. 

그럼 왜 외래키가 사용되는지 조금은 감이 오리라 생각된다. 
참고로 member_login 테이블의 데이터가 삭제될때는 상관이 없다. 
다만 member_login 의 데이터는 insert 또는 update 될때 member_info 의 id 필드를 참조하기때문에 
영향을 받는다.. 

이와같은 방식으로 
member_info 의 ID 값이 삭제나 업데이트 될때 제한을 둔다던지(restrict) 
member_info 의 ID 값이 삭제나 업데이트 될때 member_info의 ID 값을 Null 을 만들던지(set null) 한다.. 
다만 no action 은 말 그대로 아무런 동작을 하지 않는것이기에 표면상의 외래키일 뿐이다. 

참고로 Alter 문은 아래와 같이.. 
ALTER TABLE member_login Drop FOREIGN KEY fk_id; 
ALTER TABLE member_login ADD CONSTRAINT `fk_id` FOREIGN KEY (`id`) REFERENCES `member_info` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;




출처: http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=54289
에서 그대로 긁어옴..
출처: http://cloudless.tistory.com/49

댓글 없음:

댓글 쓰기