오늘의 삽질... 에러모음

[MySQL] Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails...

요호유후 2025. 1. 22. 22:05
반응형

 

오늘의 에러

 

Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails...

 

 

에러사항

실습 문제 풀이 중 아래와 같이 에러가 발생했다.

실습 문제)

고객 ID가 5인 고객의 주소를 '123 New Address, New City'로 변경하시오.
작성한 쿼리문)

UPDATE customer
SET address_id = CASE
  WHEN (SELECT address_id FROM address WHERE address = '123 New Address, New City') IS NULL THEN 0    ELSE (SELECT address_id FROM address WHERE address = '123 New Address, New City')
END
WHERE customer_id = 5;

작성한 쿼리문

에러)

Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails (`sakila`.`customer`, CONSTRAINT `fk_customer_address` FOREIGN KEY (`address_id`) REFERENCES `address` (`address_id`) ON DELETE RESTRICT ON UPDATE CASCADE)

 

 

에러원인

해당 에러는 참조테이블에 없는 값을 할당했기 때문에 발생하는 것이다.

참조 무결성에 따라서 부모키에 해당하는 값만 넣을 수 있다.

 

참조 무결성

+ 참조 무결성)

- 기본키와 참조키 간의 관계가 항상 유지됨을 보장한다.
- 참조되는 테이블의 행은, 이를 참조하는 참조키가 존재하는 한 삭제될 수 없고 기본키도 변경될 수 없다.

 

아래에 빨간색 글씨로 표시한 부분이 문제였다.

작성한 쿼리문)

UPDATE customer
SET address_id = CASE
  WHEN (SELECT address_id FROM address WHERE address = '123 New Address, New City') IS NULL THEN 0    ELSE (SELECT address_id FROM address WHERE address = '123 New Address, New City')
END
WHERE customer_id = 5;

 

작성한 쿼리문 세번째 라인을 뜯어보면,

WHEN (SELECT address_id FROM address WHERE address = '123 New Address, New City') IS NULL THEN 0 

 

() 안의 값이 NULL(값이 없다면) 이면 address_id = 0 으로 업데이트 하라는 뜻이다.

근데 아래의 첨부한 테이블을 보면 address_id 는 1부터 시작한다. 0의 값이 없다.

 

즉, 참조무결성을 위배하는 쿼리문을 짠것...

Table. address
Table. address, Table. customer 관계

 

해결

이때 해결 방법으로는,

1. 참조하는 테이블에 먼저 값을 추가한다.
2. 참조하는 테이블에 존재 하는 값으로 할당한다.
3. foreign_key_checks = 0을 사용하여 FK제약을 임시로 해제한다.
   (사용 후 무.조.건 foreign_key_checks = 1을 해줘야한다. 무!조!건)

 

위 해결 방법 중 2, 3번을 진행해 보았다. (1번은 언젠가 심심하면 해봐야즹)

나는 지금 실습 중이기때문에 2, 3번으로 진행해도 무방하겠지만

나중에 실제 서비스를 작성해야할 경우에는 1번 혹은 3번도 괜찮겠지??

2번 : 그냥 단순히 존재하는 값으로 변경
         (문제의 address = '123 New Address, New City' 내용은 무시)

UPDATE customer
SET address_id = CASE  
WHEN (SELECT address_id FROM address WHERE address = '123 New Address, New City') IS NULL THEN 1 
   ELSE (SELECT address_id FROM address WHERE address = '123 New Address, New City')
END
WHERE customer_id = 5;

해결 2

 

3번 : 쿼리문 위 아래 라인에 foreign_key_checks 를 비활성/활성 해준다.

SET foreign_key_checks = 0;
UPDATE customer
SET address_id = CASE  
WHEN (SELECT address_id FROM address WHERE address = '123 New Address, New City') IS NULL THEN 0 
   ELSE (SELECT address_id FROM address WHERE address = '123 New Address, New City')
END
WHERE customer_id = 5;
SET foreign_key_checks = 1;

해결 3

 

+ foreign_key_checks 사용 시 주의사항

foreign_key_checks 의 설정은 FK 제약과 상관없이 쿼리문을 수행하게 해준다.
따라서, 이후 실행된 쿼리문들이 FK제약에 위반된 테이블 혹은 데이터를 생성할 수 있다는 것!!

그래서
1. 단순 테스트 코드나 일회성? 코드를 작성할 때 사용하거나
2. FK제약에 위반된 테이블 혹은 데이터를 생성한 후 위반사항들을 처리해주자!
    (예를 들어 자식테이블에 부모테이블에 없는 값을 억지로? 생성/갱신 하였다면,
      이후 부모테이블에도 해당값을 데이터로 생성해주자!)

 

 

글을 정리하며...

은근 까다롭다 쿼리의 세계.... 근데 재밌당 > <

 

 

 

참고링크

https://en.wikipedia.org/wiki/Referential_integrity

https://jwprogramming.tistory.com/53

반응형