개발자
결론부터 말씀드리자면 부모테이블에 복합키를 참조하는 자식테이블에 외래키가 nullable하게 설정했을 때, 왜 부모에 없는 값을 허용하는지 이유 또는 구동 원리가 궁금합니다. 간단한 예 부모-자식 관계(FK걸려있음)일 때 부모에는 단 두 컬럼이 있으며, 복합키(두컬럼 모두 PK) 자식은 두 컬럼을 참조하는 컬럼 2개만 존재하며 nullable하다. 부모에는 (1, 'A') 라는 값이 있으면 왜 자식에 (null, '가나다') 값이 들어가도록 허용하는지에 대한 이유 또는 구동 원리가 궁금합니다! - 물론 외래키는 잘 걸려있습니다. 자세한 내용과 사례는 아래 링크를 통해서 정리를 해봤습니다. (링크는 댓글을 받기 위해 임시로 velog로 작성하였으며, 어디에 댓글을 달아주시던 상관없습니다) https://velog.io/@corder/외래키FK에-부모에-없는-값이-들어갔어요
답변 2
인기 답변
현상만으로 보면 관찰하신 내용이 틀리지 않습니다. 분명히 참조 관계를 맺었는데 부모 테이블에 없는 값이 들어갔으니까요. 그래서 "복합키를 참조하는 외래키에 NULL이 있다면 부모에 없는 값이 들어갈 수 있다" 라고 결론지으셨는데, 사실 옳은 결론은 아닙니다. 선택적 참조 관계에 대해 어느 정도를 이해하고 계실까요.. 설명의 시작 점을 찾기 조금 어려운데요. 다만.. 이 문제를 단일키가 아니라 복합키에서 찾으신 것을 보면, 단일 참조키가 NULL을 허용했을 때 여기에 NULL이 들어가는 것은 문제로 보지 않는 것 같습니다. 만약, 그렇다면 선택적 참조 관계에 대한 기본적 이해를 갖고 계시다고 볼 수 있을 테니, 부족한 부분만 설명을 이어 갈까 합니다. 먼저.. 예시로 든 수강과 출석이라는 관계는 사실 이 현상을 설명하기에 적절한 예는 아닙니다. 출석에서 수강을 참조할 때 이 관계는 보통 필수 관계이지 선택적 관계는 아니기 때문입니다. 실제 설계에서는 두 컬럼 (student_id, class_code) 모두 NULL을 허용하지 않도록 설계하겠죠. 하지만, 본문의 맥락에서 그게 중요한 것은 아니고 "복합키를 참조했을 때 참조키에 NULL을 허용하게 한 상황", 바로 이 때 벌어지는 한 가지 현상에 대한 것이겠죠. 여기서 다시 한 번 확인! student_id와 class_code 둘 다 NULL인 값을 attendance 테이블에 INSERT 할 때, 이때도 참조키 오류가 발생하지 않고 들어가는데요. 이것도 문제라고 생각하시나요? 혹시나 이것도 이상하다고 하시면, 선택적 관계가 무엇이고 왜 필요한지 확인하는 것이 먼저인데요. 위에 전제한 것처럼 이것은 이미 이해하고 계시리라 생각하겠습니다. 그렇다면 문제가 되는 것은 이제 한 가지입니다. 왜 두 컬럼 중 하나의 컬럼만 NULL일 때도 INSERT가 성공하는가? 그래서 내리신 결론은 "복합키를 참조하는 외래키에 NULL이 있다면 부모에 없는 값이 들어갈 수 있다" 인 것 같습니다. 그런데 올바른 결론은 "외래키가 NULL을 허용한다면 부모 테이블을 참조하지 않을 수 있다" 입니다. 첫 째, 복합키와 단일키는 이 문제와 관련이 없습니다. 둘 째, 부모에 없는 값이 들어간 것이 아니라 부모 테이블을 참조하지 않는 값이 들어간 것입니다. 바꿔말하면 "참조 관계에 있지만 부모 테이블에 없는 값이 들어간 것"이 아니라, "참조 관계가 성립하지 않는 종류의 값이 들어간 것"입니다. 이게 무슨 뜻일까요? attendance 테이블이 enrollment 테이블을 참조할 때 참조키가 (단일키이든 복합키이든) NULL을 허용하도록 설계했기 때문에, 두 테이블의 참조 관계는 "선택적"이 됩니다. 즉, enrollment 테이블을 참조하지 않는 행(row)도 attendance 테이블에 넣을 수 있게 한다는 뜻입니다. 하지만 선택적이더라도 두 컬럼 (student_id & class_code) 모두에 값이 들어 있다면, 이 값의 조합은 반드시 enrollment 테이블에 딱 1개의 행으로 존재해야 합니다. 자, 여기가 본론입니다. 두 컬럼 중 하나가 NULL이라면? 결론부터 얘기하면.. 이 때는 참조 관계가 성립하지 않습니다. 그런 값의 조합은 enrollment 테이블에서 1개의 행을 찾게 해주는 기본키 또는 유일키가 될 수 없기 때문입니다. 더구나, 이 예제에서는 유일키가 아니라 기본키를 참조하는 참조키이기 때문에.. 애초에 NULL이 포함된 조합으로는 enrollment에 존재하는 것 자체가 불가능한 값이죠. 바꿔 말하면, RDB의 참조 관계는 참조키의 값으로 부모 테이블을 검색했을 때 특정 1개의 행을 식별(= 키)할 수 있을 때만 그 관계가 성립합니다. 그런데 NULL이 섞이면 그런 행이 부모 테이블에 1개만 존재하는 것을 보장할 수 없기 때문에 참조 관계가 아닌 것으로 판단하는 겁니다. 이해하는데 필요한 배경 지식이 하나 더 있는데.. 바로 NULL 값의 특성입니다. NULL은 어떤 값과 조합해도 그 결과가 NULL이 되고, NULL은 NULL과 비교할 수 없다는 사실입니다. 간단한 예로 1 + NULL은 NULL 입니다. CONCAT(NULL, 'abc') 역시 NULL인데.. 어쨌든 NULL을 다른 값과 연산한 결과는 NULL이고, 마찬가지로 NULL인 컬럼을 다른 컬럼과 조합하면 그 결과 역시 NULL로 평가합니다. 그런데 NULL은 NULL과 같지도 않고 다르지도 않습니다. NULL = NULL도 false이고, NULL <> NULL도 false 라는 뜻입니다. 따라서, 어떤 테이블에서 복합키 컬럼에 NULL이 포함되면.. 그 행은 어떤 다른 행과도 비교가 불가능하고, 이런 이유에서라도 참조 관계가 성립하지 않겠죠. 글이 길어졌는데, 이해하시는데 도움 되셨으면 좋겠습니다.
고동하
작성자
진학사 풀스택 개발자 • 2024년 02월 19일
정말 감사합니다! 부모 테이블을 참조하지 않는다는 개념을 말씀해 주신 덕분에 궁금증이 풀렸습니다! 혹시 적어주신 글을 읽고 궁금한 점이 2가지가 생겨서 조심스럽게 여쭤보려 합니다ㅎㅎ.. 1. 복합키를 선택적 참조로 모델링한 경우(예)를 알고 싶습니다. 글 내용에서의 모델링은 말씀하신 대로 강제로 만든 케이스입니다! 당장 생각나는 선택적 참조를 사용하는 예들의 경우, 참조 컬럼이 한 개인 경우들만 떠오르네요... 아마도 제 생각에는 발생할 수 있는 케이스들을 정의해 놓은 상태에서 모델링을 하거나(자식에 들어갈 수 있는 모든 상태를 데이터로 관리하는 경우), 경우에 따라 새로운 PK를 만들기 때문에 해당 경우가 적은 것 같아 보입니다. 혹시 복합키를 선택적 참조로 모델링한 경우가 있으실까요? 2. 말씀해주신 답변 같이 깊은 내용(제 기준ㅎㅎ)을 공부하고 싶다면 뭘(공부하는 방식이나 참고할만한 서적 등) 참고해야 될까요? (너무 광범위한 질문이라 답변하시기 부담스러우실 것 같습니다...ㅎㅎ) "그런데 NULL이 섞이면 그런 행이 부모 테이블에 1개만 존재하는 것을 보장할 수 없기 때문에 참조 관계가 아닌 것으로 판단하는 겁니다." > 이렇게 판단하는 로직이나 근거들을 어디서 얻을 수 있을까가 궁금합니다!
김도열
DB Designer & SQLer • 2024년 02월 19일
@고동하 1. 선택적 참조는 자주 사용하지만 복합키를 참조하는 경우는 상대적으로 드물고, 이 두 가지를 동시에 사용해야 하는 경우는 아마 없을 겁니다. 테이블을 그렇게 설계할 수는 있겠지만 대개 더 나은 다른 방법이 있을테니까요. 2. 모든 것이 그렇지만.. 이론 -> 실무 -> 이론의 순서로 단단해 지는 것 같습니다. 제가 본 모델링 책은 오래돼서 찾을 수 없고 추천 드릴 수 없지만, 실무에 별 문제를 겪지 않을 때 쯤.. 내가 하는 방식이 이론에 어긋나지 않나 궁금해서 정독했고 도움이 되었습니다. 뭐랄까.. 경험과 직관에 의존해 설계했던 하나 하나의 방식이 실제로 "이름"을 갖고 있다는 것이 좀 신기했죠. 책을 추천해 드리면 좋은데, 앞서 말씀드린 것처럼.. 설계 책을 다시 볼 이유가 딱히 없어서 요즘 책은 잘 모르겠네요. 책을 보는게 필수라고 생각하진 않지만 너무 심오한(?) 책은 좀 피해서 찾아 보시는 건 나쁘지 않을 것 같습니다. 그리고 나머지는 지금 하시는 것처럼, 현상을 관찰하고 그 현상의 이유를 하나 씩 찾아가며 차곡 차곡 쌓아 나가면 되지 않을까요? 저도 회고해보면 딱히 공부에 매진한 적은 없는 것 같습니다. 지식이 휘발되지 않고 쌓이는 습관으로 블로깅은 정말 좋은 방법이죠. 그리고 좀 더 확실한 방법은 남에게 알려주는 것이라고 생각합니다.
인기 답변
NULL은 데이터 자체가 없다는 것을 의미합니다. Nullable로 설정하셨으니, 해당 데이터는 비어있어도 된다는 뜻입니다. 데이터 자체가 없다면 부모와의 관계를 논하지 않겠다는 뜻이죠. Unique key도 위 맥락과 똑같습니다. Nullable Unique key는 중복은 막지만, NULL 데이터는 여러 개 들어가도 괜찮습니다. (DBMS마다 차이가 있을 수 있으니, 꼭 엔진마다 위 내용을 확인하셔야 합니다.) 그렇다면 이런 걸 왜 허용할까요? 라는 의문이 남습니다. 처음엔 관계가 없거나, 나중에 관계가 사라지는 경우가 종종 있기 때문입니다. 예를 들어 스포츠를 알아보겠습니다. 축구, 농구, e-스포츠 등 스포츠 선수들은 ”소속팀“ - ”선수“ 관계를 보통 가집니다. 하지만 FA 상태에 있는 선수들이 종종 있습니다. 이들은 소속팀이 없는 선수들입니다. 이제 막 데뷔한 신인이나 소속팀과의 계약이 끝난 선수들이 종종 FA 상태가 되죠. 이럴 때 FK가 NULL을 허용하지 않는다면, 소프트웨어는 혼란스러울 겁니다. 분명 논리적으로 소속팀이 없어야하는데, 물리적으로 반영해줄 수 없는 상태가 돼죠. 일부러 FA 라는 소속팀을 만들자니, 그러면 “소속팀”이라는 엔티티가 가져야할 다른 관계들이 문제될 수 있겠죠. DB에 데이터를 저장하기 위한 규격은 데이터 모델링을 통해 만듭니다. 스포츠에서의 사례처럼 데이터 모델링을 하는 과정에서, 논리적인 흐름을 물리적으로 반영하기 위해서 FK나 Unique가 nullable을 허용하는 것이지 않을까 합니다.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!
현직자들의 명쾌한 답변을 얻을 수 있어요.
이미 회원이신가요?
커리어리 AI 봇
GPT가 달아주는 답변입니다.
2024년 02월 15일
즉, 외래 키에서 NULL 값을 허용하는 이유는 외래 키의 주요 목적 중 하나인 참조 무결성을 유지하는 동시에 다양한 데이터 상태를 나타낼 수 있기 때문입니다. 외래키가 nullable 한 경우, 복합키를 구성하는 개별 컬럼들은 각각 분리되어 해석됩니다. 즉, (null, 'A')라고 입력된다면 첫 번째 필드에 해당하는 부모 테이블 필드를 참조하지 않고 널을 저장할 수 있다는 것입니다. 반면 'A'는 부모테이블에서 일치하는 값이 있어야합니다. 단, 이 기능이 모든 상황에서 바람직한 것은 아닙니다. 외래 키 컬럼에 NULL을 허용하게 되면 데이터의 일관성이 깨질 수 있습니다. 가능하다면 NOT NULL 제약 조건과 함께 DEFAULT 값을 설정하여 이 문제를 방지하는 것이 바람직합니다. 또한, 데이터베이스 설계 시 외래키가 Null 값을 가질 수 없게 하는 것이 좋습니다. 그 이유는 Null 값을 가진 외래키 필드로 부터 어느 레코드도 찾을 수 없기 때문입니다. 실제로 많은 RDBMS(Relational Database Management System)에서는 외래키로 Null 값을 허용하지 않습니다. 맨 처음에 말씀드린 것처럼 이것은 데이터베이스의 설계와 사용 파트에 따라 크게 달라집니다. 어떤 상황에서는 Null을 허용하는 것이 유리할 수 있지만, 다른 상황에서는 그렇지 않을 수 있습니다.
지금 가입하면 모든 질문의 답변을 볼 수 있어요!