2011-03-16 15 views
5

Estoy trabajando en la función de migración. Lee los datos de la tabla anterior y los inserta en la nueva. Todas esas cosas trabajando en el hilo de fondo con baja prioridad.error sqlite y 'restricción falló' al seleccionar e insertar al mismo tiempo

Mis pasos en el pseudo código.

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) 

Siempre estoy poniendo 'restricción falló error en sqlite3_step (insert statement). ¿Por qué sucedió y cómo podría solucionar eso?

UPD: Según tengo entendido, esto ha sucedido porque el hilo de fondo usa el mango de db abierto en el hilo principal. Comprobando que adivinar ahora.

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

Gracias por la actualización. Edité mi respuesta y agregué información más útil (espero). –

Respuesta

7

Probablemente significa que su instrucción de inserción está violando una restricción en la nueva tabla. Podría ser una restricción de clave principal, una restricción única, una restricción de clave externa (si está usando PRAGMA foreign_keys = ON;), y así sucesivamente.

Lo soluciona eliminando la restricción, corrigiendo los datos o soltando los datos. Dejar caer la restricción suele ser una cosa mala, pero eso depende de la aplicación.

¿Hay alguna razón de peso para copiar datos una fila a la vez en lugar de como un conjunto?

INSERT INTO new_table 
SELECT column_list FROM old_table; 

Si necesita ayuda para identificar la restricción, editar su pregunta original, y después de la salida de estos dos consultas SQLite.

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

Actualización: Sobre la base de la salida de esos dos consultas, sólo veo una limitación - la restricción de clave principal en cada tabla. Si no ha creado desencadenantes en estas tablas, la única restricción que puede fallar es la restricción de clave principal. Y la única forma en que la restricción puede fallar es si intenta insertar dos filas que tengan el mismo valor para 'pk'.

Supongo que podría suceder de diferentes maneras.

  • La tabla anterior tiene valores duplicados en la columna 'pk'.
  • El código que realiza su migración altera o inyecta un valor duplicado antes de insertar datos en su nueva tabla .
  • Otro proceso, que posiblemente se ejecuta en una computadora diferente, está insertando o actualizando datos sin su conocimiento.
  • Otras razones que no he pensado aún. :-)

Puede determinar si hay valores duplicados de 'pk' en la tabla anterior ejecutando esta consulta.

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

usted podría considerar tratar de migrar manualmente los datos utilizando INSERT INTO . . . SELECT . . . Si eso no funciona, añadir una cláusula WHERE para reducir el tamaño del conjunto hasta aislar los datos erróneos.

+1

no. No estoy usando foreign_keys. y hay otro hilo que realiza inserciones con éxito. ahora estoy incluso llenar insertar siempre con la misma información. y la situación no cambió. el segundo subproceso siempre falla al insertar datos. inserciones protegidas por mutexes por lo que solo una posible a la vez. –

+0

Se agregaron instrucciones para extraer el SQL DDL de SQLite. Edite su pregunta original e inserte los resultados de esas dos consultas. –

+0

en UPD agregué que estoy tratando de ejecutar insertar con los mismos datos en 2 hilos muchas veces. El primer hilo (donde se abrió sqlite3 *) funciona siempre bien, insertar en el segundo no funcionó. como se puede ver en los esquemas de tablas, pk es único en ambas tablas. –

1

Por si alguien aterriza aquí buscando el mensaje de error "Restricción fallida", asegúrese de que el tipo de columna Id sea INTEGER, no INTEGER (0, 15) o algo así.

Antecedentes

Si la tabla tiene una columna llamada Id, con el tipo de INTEGER y establecer como clave principal, SQLite lo trata como un alias para la columna integrada RowId. Esta columna funciona como una columna de incremento automático. En mi caso, esta columna funcionaba bien hasta que algún diseñador de tablas (probablemente el creado por SQLite para Visual Studio) cambió el tipo de columna de INTEGER a INTEGER (0, 15) y de repente mi aplicación comenzó a lanzar Constraint failed excepción.

Cuestiones relacionadas