2012-03-26 22 views
11

Actualmente estoy tratando de crear una base de datos sqlite donde puedo importar una tabla desde otra base de datos sqlite (no puedo adjuntar) y agregar algunos datos adicionales a cada columna.INSERTAR O REEMPLAZAR + clave externa ELIMINAR CASCADA funciona demasiado bien

ya que no hay INSERT OR UPDATE me ocurrió esto:
Estaba pensando en dividir los datos en dos tablas y unirse a ellos después, así que sólo puedo volcar toda la importación en una tabla reemplazar todo lo que ha cambiado y gestionar el extra datos por separado ya que eso no cambia en la importación.

La primera tabla (vamos a llamarlo base_data) se vería como

local_id | remote_id | base_data1 | base_data2 | ... 
---------+-----------+------------+------------+---- 

además de la local_id todo lo que acaba de ser un espejo de la base de datos remota (probablemente voy a añadir una marca de tiempo de sincronización, pero eso no importa ahora).

La segunda tabla se vería similar pero tiene remote_id conjunto como clave externa

remote_id | extra_data1 | extra_data2 | ... 
----------+-------------+-------------+---- 

    CREATE TABLE extra_data (
     remote_id INTEGER 
      REFERENCES base_data(remote_id) 
      ON DELETE CASCADE ON UPDATE CASCADE 
      DEFERRABLE INITIALLY DEFERRED, 
     extra_data1 TEXT, 
     extra_data2 TEXT, 
     /* etc */ 
    ) 

Ahora mi idea era simplemente INSERT OR REPLACE INTO base_data ... valores porque la base de datos puedo importar archivos desde no tiene ninguna marca de tiempo de sincronización o en absoluto y yo tendría que comparar todo para averiguar qué fila tengo para UPDATE/qué a INSERT.

Pero aquí está el problema: INSERT OR REPLACE es en realidad un DELETE seguido de un INSERT y la parte de eliminación activa la clave externa ON DELETE el que pensé que podría evitar que al hacer la restricción DEFERRED. No funciona si envuelvo INSERT OR REPLACE en una transacción. Siempre borro mis datos extra, aunque existe la misma clave externa después de la declaración.

¿Es posible detener ON DELETE para disparar hasta que se termine INSERT OR REPLACE? Tal vez algún modo de transacción especial/pragma?

Respuesta

3

Parece trabajo si se sustituye la parte ON DELETE CASCADE por un gatillo como:

CREATE TRIGGER on_delete_trigger 
    AFTER DELETE ON base_data 
    BEGIN 
     DELETE FROM extra_data WHERE extra_data.remote_id=OLD.remote_id; 
    END; 

que desencadenan solamente se desencadena por una declaración DELETE y debería resolver mi problema hasta ahora.

(respuesta proporcionada por la OP en la pregunta)

Otros detalles por jmathew, citando el documentation:

Cuando la estrategia de resolución REPLACE conflicto elimina filas con el fin de satisfacer una restricción, eliminar activa desencadena si y solo si activadores recursivos están habilitados.

0

Suponiendo que solo tiene una sola relación de clave externa en una clave primaria en su tabla referenciada (como lo hace en su ejemplo), esta resultó ser una solución bastante sencilla para mí.

Simplemente desactive las comprobaciones de claves foráneas, ejecute la consulta de reemplazo y vuelva a habilitar las claves foráneas.

Si la consulta de reemplazo es la única consulta que se ejecuta mientras las claves externas están deshabilitadas, puede estar seguro de que no se cometerán errores en las claves externas. Si está insertando una nueva fila, nada habrá tenido la oportunidad de vincularse a ella todavía y si está reemplazando una fila, la fila existente no se eliminará o su clave principal cambiará por la consulta, por lo que la restricción se mantendrá. una vez que se vuelven a habilitar las claves externas.

código SqlLite ve algo como esto:

PRAGMA foreign_keys=OFF; 
INSERT OR REPLACE ...; 
PRAGMA foreign_keys=ON; 
Cuestiones relacionadas