2011-03-16 1 views
5

마이그레이션 기능을 사용하고 있습니다. 그것은 이전 테이블에서 데이터를 읽고 새로운 테이블에 삽입합니다. 그 모든 것들은 우선 순위가 낮은 백그라운드 스레드에서 작동합니다.동시에 선택 및 삽입하는 동안 sqlite 및 '제약 조건 실패'오류가 발생했습니다.

의사 코드의 내 단계.

sqlite3_prepare_stmt (select statement) 
sqlite3_prepare_stmt (insert statement) 

while (sqlite3_step (select statement) == SQLITE_ROW) 
{ 
    get data from select row results 
    sqlite3_bind select results to insert statement 
    sqlite3_step (insert statement) 
    sqlite3_reset (insert statement) 
} 

sqlite3_reset (select statement) 

sqlite3_step (insert statement)에 '제약 실패'오류가 항상 나타납니다. 왜 그런 일이 일어나고 어떻게 해결할 수 있을까요?

UPD : 배경 스레드가 주 스레드에서 열린 db 핸들을 사용하기 때문에 문제가 발생한다는 것을 알고 있습니다. 지금 그 추측을 확인하십시오.

UPD2는 :

sqlite> select sql from sqlite_master where tbl_name = 'tiles'; 
CREATE TABLE tiles('pk' INTEGER PRIMARY KEY, 'data' BLOB, 'x' INTEGER, 'y' INTEGER, 'z' INTEGER, 'importKey' INTEGER) 
sqlite> select sql from sqlite_master where tbl_name = 'tiles_v2'; 
CREATE TABLE tiles_v2 (pk int primary key, x int, y int, z int, layer int, data blob, timestamp real) 
+0

감사합니다. 나는 나의 대답을 편집하고 좀 더 유용한 정보를 원했다. –

답변

7

그것은 아마 삽입 문은 새 테이블에 제약 조건을 위반하는 것을 의미한다. 기본 키 제약 조건, 고유 제약 조건, 외래 키 제약 조건 (PRAGMA foreign_keys = ON;을 사용하는 경우) 등이 될 수 있습니다.

제약 조건을 삭제하거나, 데이터를 수정하거나, 데이터를 삭제하여 문제를 해결할 수 있습니다. 제약 조건을 없애는 것은 일반적으로 나쁜 일이지만 응용 프로그램에 따라 다릅니다.

세트가 아닌 한 번에 한 행씩 데이터를 복사해야 할 강력한 이유가 있습니까?

INSERT INTO new_table 
SELECT column_list FROM old_table; 

제약 조건을 확인하는 데 도움이 필요하면 원래 질문을 편집하고이 두 가지 SQLite 쿼리의 출력을 게시하십시오.

select sql from sqlite_master where tbl_name = 'old_table_name'; 
select sql from sqlite_master where tbl_name = 'new_table_name'; 


업데이트 : 그 두 쿼리의 출력을 바탕으로, 나는 단지 하나 개의 제약 조건 참조 - 각 테이블의 기본 키 제약 조건을. 이 테이블에 트리거를 작성하지 않은 경우 실패 할 수있는 유일한 제한 조건은 기본 키 제한 조건입니다. 그리고 제약 조건이 실패하는 유일한 방법은 'pk'에 대해 동일한 값을 가진 두 개의 행을 삽입하려고하는 경우입니다.

나는 그것이 몇 가지 다른 방식으로 발생할 수 있다고 생각합니다.

  • 이전 테이블의 값은 의 'pk'열에 있습니다.
  • 은 새로운 테이블에 데이터를 삽입하기 전에 중복 값 을 변경하거나 주입합니다.
  • 다른 컴퓨터에서 (다른 컴퓨터에서 실행 중일 수 있음)을 실행중인 다른 프로세스가 알려지지 않은 채로 또는 데이터를 업데이트 중입니다.
  • 다른 이유는 아직 생각하지 못했습니다. :-)

이 쿼리를 실행하면 이전 테이블에 'pk'값이 중복되어 있는지 확인할 수 있습니다.당신이 실패 할 경우 수동으로 INSERT INTO . . . SELECT . . .를 사용하여 데이터를 마이그레이션하려고 고려해 볼 수 있습니다

select pk 
from old_table_name 
group by pk 
having count() > 1; 

, 당신은 나쁜 데이터를 분리 할 때까지 세트의 크기를 줄이기 위해 WHERE 절을 추가합니다.

+1

no. foreign_keys를 사용하고 있지 않습니다. 삽입을 성공적으로 수행하는 다른 스레드가 있습니다. 이제는 항상 같은 데이터로 채워 넣기까지했습니다. 상황은 바뀌지 않았다. 두 번째 스레드는 항상 데이터를 삽입하지 못합니다. 뮤텍스에 의해 보호되는 삽입은 한 번만 가능합니다. –

+0

SQLite에서 SQL DDL을 추출하는 방법이 추가되었습니다. 원래 질문을 편집하고 두 쿼리의 결과를 삽입하십시오. UPD에서 –

+0

나는 2 개의 스레드에서 동일한 데이터를 여러 번 삽입하려고 시도하고 있다고 덧붙였다. 첫 번째 스레드 (sqlite3 *가 열린 곳)는 항상 정상적으로 작동하며, 두 번째 스레드에서 삽입하면 작동하지 않습니다. 테이블 스키마에서 볼 수 있듯이 - pk는 두 테이블 모두에서 고유합니다. –

1

"Constraint failed"오류 메시지를 찾는 사용자가 여기있는 경우 Id 열의 유형이 이 아니고 INTEGER (0, 15)이 아닌지 확인하십시오. 테이블 유형 INTEGER으로, Id 이름 및 기본 키로 설정 열이있는 경우

배경

은, SQLite는 기본 제공 열 RowId의 별칭으로 처리합니다. 이 열은 자동 증가 열과 같이 작동합니다. 필자의 경우, 일부 테이블 디자이너 (아마도 Visual Studio 용 SQLite 사용자가 만든 것)가 INTEGER에서 INTEGER (0, 15)으로 변경되어 갑자기 내 응용 프로그램이 Constraint failed 예외를 던지기 시작했을 때까지이 열은 잘 작동했습니다.