-
SQLite에 외래 키를 썼는데 잘못된 참조가 들어가는 이유Data Analysis 2026. 10. 5. 00:21728x90반응형

파일이 같다는 사실만으로 연결 B의 외래 키 설정을 알 수는 없습니다. SQLite 테이블에
REFERENCES가 있는데 없는 부모 ID도 저장된다면, 쓰기에 사용한 연결에서PRAGMA foreign_keys;를 조회하세요. 외래 키는 선언과 함께 연결별 활성화 상태를 확인해야 합니다.화면에서는 잘 막히는데 CSV 가져오기에서만 잘못된 값이 들어가는 경우도 같은 순서로 좁힐 수 있습니다. 두 기능이 같은 DB 파일을 사용하더라도 서로 다른 연결을 만들 수 있기 때문입니다.
책이 없는 분류를 가리키는 예시
분류 10이 있고 각 책에는 분류가 반드시 하나 있어야 한다고 가정하겠습니다. 아래 SQL은 빈 테스트 DB용 설명 예시이며 운영 자료에 실행한 결과가 아닙니다.
CREATE TABLE categories ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ); CREATE TABLE books ( id INTEGER PRIMARY KEY, category_id INTEGER NOT NULL REFERENCES categories(id) ); INSERT INTO categories VALUES (10, '개발');NOT NULL은 분류를 비워 두지 못하게 하고,REFERENCES categories(id)는 기록한 분류가 존재하도록 요구합니다. 분류 99는 부모에 없으므로 외래 키 검사가 켜진 연결에서 다음 입력은 거부돼야 합니다.INSERT INTO books VALUES (1, 99);그런데 이 입력이 저장됐다면
CREATE TABLE문구를 다시 추가하기 전에 지금 연결의 상태를 읽습니다.PRAGMA foreign_keys;조회값이 0이면 검사 꺼짐, 1이면 켜짐입니다. 결과 행 자체가 나오지 않으면 사용하는 SQLite의 버전과 컴파일 옵션부터 확인합니다. SQLite 외래 키 활성화 문서는 지원 여부와 연결별 활성화를 구분하며 기본값에 의존하지 않도록 안내합니다.
설정 명령이 실행됐는데도 0인 경우
지원되는 연결에서는 아래처럼 설정하고 바로 조회할 수 있습니다.
PRAGMA foreign_keys = ON; PRAGMA foreign_keys;단, 트랜잭션 안에서는 설정을 바꿀 수 없습니다. SQLite는 이때 오류를 내지 않고 변경을 적용하지 않습니다. 초기화 함수가 호출됐다는 로그만으로는 충분하지 않은 이유입니다. foreign_keys PRAGMA
예를 들어 가져오기 코드가
BEGIN을 실행한 뒤 위 초기화 함수를 호출한다면 순서가 늦습니다. 새 연결이 만들어진 직후, 트랜잭션을 시작하기 전에 활성화하고 1을 확인하는 구조로 옮겨야 합니다. 진행 중인 운영 작업을 임의로 커밋해서 설정 공간을 만드는 방식으로 고치지는 않습니다.ORM이나 연결 풀을 쓴다면 초기화 훅이 각 새 연결에 실행되는지 확인합니다. 앱 시작 때 연결 A 하나에서만 켠 뒤 별도 가져오기 연결 B를 만들면 B의 상태는 여전히 별도로 남습니다. 재연결, 배치 작업, 마이그레이션 도구가 연결을 만드는 위치도 찾을 대상입니다.
수정 확인은 B에서 설정값을 읽고 테스트용 잘못된 참조를 넣는 두 단계로 합니다. 조회가 1이라는 결과와 잘못된 입력이 실제로 거부되는 결과를 함께 보면, 다른 연결을 점검하고 있었던 실수도 찾기 쉽습니다.
이미 들어간 99는 자동으로 고쳐지지 않습니다
외래 키를 켠 뒤에도 기존 데이터 검사는 남습니다. 부모 없는 책이 이전에 저장됐다면 그 책의 분류가 자동으로 10으로 바뀌거나 삭제되지는 않습니다.
PRAGMA foreign_key_check;이 명령은 발견한 위반마다 자식 테이블, 행 식별 정보, 부모 테이블, 외래 키 번호를 반환합니다. 일반적인 rowid 테이블에서 앞의 잘못된 책이 남았다면
books와 해당 행 정보가 조사 대상입니다.WITHOUT ROWID테이블에서는 행 식별 열이 NULL일 수 있습니다. foreign_key_check 결과 형식결과를 보고 바로 행을 지우기보다 입력 근거를 확인해야 합니다. ‘개발’ 분류가 실제로 99에서 10으로 바뀐 것인지, 분류 가져오기가 빠진 것인지에 따라 복구가 달라집니다. 잘못된 ID이면 수정하고, 누락된 부모 자료라면 검증한 부모를 먼저 복구할 수 있습니다. 이는 데이터의 의미로 정할 문제라 검사 명령이 대신 결정하지 않습니다.
수정한 뒤
foreign_key_check를 다시 실행해 해당 위반이 사라졌는지 확인합니다. 기존 자료 검사와 앞으로의 쓰기 연결 설정은 별도 기록으로 남깁니다. 한쪽이 정상이어도 다른 쪽이 빠지면 같은 문제가 반복될 수 있습니다.integrity_check가 ok여도 외래 키는 다시 봅니다
PRAGMA integrity_check;는 외래 키 위반 검사를 포함하지 않습니다. 파일의 일반 무결성을 점검했다는 결과만으로 책 99의 참조가 올바르다고 볼 수 없습니다. SQLite integrity_check의 검사 범위또 제약을 지연 검사하도록 선언했다면 실패 시점이 INSERT 직후가 아니라 COMMIT일 수 있습니다. 본문의
books는 기본 즉시 검사 예시입니다. 테스트에서 INSERT가 성공했다고 기록할 때는 트랜잭션 종료까지 성공했는지와DEFERRABLE선언 여부도 함께 봅니다. 즉시·지연 외래 키2026년 9월 28일 SQLite 공식 문서를 기준으로 정리했습니다. 실제 앱에 반영할 위치는 사용하는 연결 라이브러리에 따라 달라집니다. 문제가 난 쓰기 경로에서 연결 초기화, 설정 조회, 기존 위반 검사를 차례로 확인하면 어느 부분을 고쳐야 하는지 구분할 수 있습니다.
728x90반응형'Data Analysis' 카테고리의 다른 글
제외 목록에 NULL 하나 넣었더니 SQL 결과가 사라지는 이유 (1) 2026.10.05 UNIQUE를 걸었는데 빈 값이 여러 개 들어가는 이유 (0) 2026.10.05 timestamptz에 저장한 시간대 이름은 어디로 갔을까 (0) 2026.10.05 DuckDB-Wasm이란? CSV를 서버에 올리지 않고 분석하는 구조 (0) 2026.09.11 P-Value, T-Test, Z-Test 설명 (0) 2023.06.27