¿Cómo agrego una clave externa a una tabla SQLite existente?

Tengo la siguiente tabla:

CREATE TABLE child( id INTEGER PRIMARY KEY, parent_id INTEGER, description TEXT); 

¿Cómo agrego una restricción de clave externa en parent_id ? Supongamos que las claves foráneas están habilitadas.

La mayoría de los ejemplos asumen que estás creando la tabla; me gustaría agregar la restricción a una existente.

No puedes.

Aunque la syntax de SQL-92 para agregar una clave externa a su tabla sería la siguiente:

 ALTER TABLE child ADD CONSTRAINT fk_child_parent FOREIGN KEY (parent_id) REFERENCES parent(id); 

SQLite no admite la variante ADD CONSTRAINT del comando ALTER TABLE ( sqlite.org: Funciones de SQL que SQLite no implementa ).

Por lo tanto, la única forma de agregar una clave foránea en sqlite 3.6.1 es durante CREATE TABLE siguiente manera:

 CREATE TABLE child ( id INTEGER PRIMARY KEY, parent_id INTEGER, description TEXT, FOREIGN KEY (parent_id) REFERENCES parent(id) ); 

Desafortunadamente, tendrá que guardar los datos existentes en una tabla temporal, soltar la tabla anterior, crear la nueva tabla con la restricción FK y luego copiar los datos de la tabla temporal. ( sqlite.org – Preguntas frecuentes: Q11 )

Puede agregar la restricción si modifica la tabla y agrega la columna que usa la restricción.

Primero, crea una tabla sin el parent_id:

 CREATE TABLE child( id INTEGER PRIMARY KEY, description TEXT); 

Luego, alter table:

 ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id); 

Por favor, consulte https://www.sqlite.org/lang_altertable.html#otherralter

Los únicos comandos de modificación de esquema soportados directamente por SQLite son los comandos “renombrar tabla” y “agregar columna” que se muestran arriba. Sin embargo, las aplicaciones pueden realizar otros cambios arbitrarios en el formato de una tabla mediante una secuencia simple de operaciones. Los pasos para realizar cambios arbitrarios en el diseño del esquema de alguna tabla X son los siguientes:

  1. Si las restricciones de clave externa están habilitadas, deshabilítelas usando PRAGMA foreign_keys = OFF.
  2. Comience una transacción.
  3. Recuerde el formato de todos los índices y disparadores asociados con la tabla X. Esta información será necesaria en el paso 8 a continuación. Una forma de hacerlo es ejecutar una consulta como la siguiente: SELECT type, sql FROM sqlite_master WHERE tbl_name = ‘X’.
  4. Use CREATE TABLE para construir una nueva tabla “new_X” que tenga el formato revisado deseado de la tabla X. Asegúrese de que el nombre “new_X” no colisione con ningún nombre de tabla existente, por supuesto.
  5. Transfiera contenido de X a new_X usando una instrucción como: INSERT INTO new_X SELECT … FROM X.
  6. Suelta la tabla anterior X: DROP TABLE X.
  7. Cambia el nombre de new_X a X usando: ALTER TABLE new_X RENAME TO X.
  8. Use CREATE INDEX y CREATE TRIGGER para reconstruir índices y desencadenantes asociados con la tabla X. Quizás utilice el formato anterior de los desencadenadores e índices guardados desde el paso 3 anterior como una guía, haciendo los cambios apropiados para la alteración.
  9. Si alguna vista se refiere a la tabla X de una manera que se ve afectada por el cambio de esquema, entonces suelte esas vistas usando DROP VIEW y recíclelas con los cambios necesarios para acomodar el cambio de esquema usando CREATE VIEW.
  10. Si las restricciones de clave externa se habilitaron originalmente, ejecute PRAGMA foreign_key_check para verificar que el cambio de esquema no rompió ninguna restricción de clave externa.
  11. Confirme la transacción iniciada en el paso 2.
  12. Si las restricciones de claves externas se habilitaron originalmente, vuelva a habilitarlas ahora.

El procedimiento anterior es completamente general y funcionará incluso si el cambio de esquema hace que cambie la información almacenada en la tabla. Entonces, el procedimiento completo anterior es apropiado para eliminar una columna, cambiar el orden de las columnas, agregar o eliminar una restricción ÚNICA o PRIMARY KEY, agregar restricciones CHECK o FOREIGN KEY o NOT NULL, o cambiar el tipo de datos para una columna, por ejemplo.

Si está utilizando el complemento sqlite-manager de Firefox, puede hacer lo siguiente:

En lugar de dejar caer y crear la tabla de nuevo, uno puede modificarlo así.

En el cuadro de texto Columnas, haga clic con el botón derecho en el último nombre de columna que aparece para mostrar el menú contextual y seleccione Editar columna. Tenga en cuenta que si la última columna en la definición de TABLE es PRIMARY KEY, será necesario agregar primero una nueva columna y luego editar el tipo de columna de la nueva columna para agregar la definición de FOREIGN KEY. Dentro del cuadro Tipo de columna, agregue una coma y

 FOREIGN KEY (parent_id) REFERENCES parent(id) 

definición después del tipo de datos. Haga clic en el botón Cambiar y luego haga clic en el botón Sí en el cuadro de diálogo Operación peligrosa.

Referencia: Sqlite Manager

Sí, puedes, sin agregar una nueva columna. Debe tener cuidado de hacerlo correctamente para evitar corromper la base de datos, por lo que debe hacer una copia de seguridad completa de su base de datos antes de intentar esto.

para su ejemplo específico:

 CREATE TABLE child( id INTEGER PRIMARY KEY, parent_id INTEGER, description TEXT ); --- create the table we want to reference create table parent(id integer not null primary key); --- now we add the foreign key pragma writable_schema=1; update SQLITE_MASTER set sql = replace(sql, 'description TEXT)', 'description TEXT, foreign key (parent_id) references parent(id))' ) where name = 'child' and type = 'table'; --- test the foreign key pragma foreign_keys=on; insert into parent values(1); insert into child values(1, 1, 'hi'); --- works insert into child values(2, 2, 'bye'); --- fails, foreign key violation 

o más generalmente:

 pragma writable_schema=1; // replace the entire table's SQL definition, where new_sql_definition contains the foreign key clause you want to add UPDATE SQLITE_MASTER SET SQL = new_sql_definition where name = 'child' and type = 'table'; // alternatively, you might find it easier to use replace, if you can match the exact end of the sql definition // for example, if the last column was my_last_column integer not null: UPDATE SQLITE_MASTER SET SQL = replace(sql, 'my_last_column integer not null', 'my_last_column integer not null, foreign key (col1, col2) references other_table(col1, col2)') where name = 'child' and type = 'table'; pragma writable_schema=0; 

De cualquier manera, es probable que desee ver primero cuál es la definición de SQL antes de realizar cambios:

 select sql from SQLITE_MASTER where name = 'child' and type = 'table'; 

Si usa el método replace (), puede resultarle útil, antes de ejecutar, probar primero su comando replace () ejecutando:

 select update(sql, ...) from SQLITE_MASTER where name = 'child' and type = 'table'; 

¡Usted puede!

Pruebe el siguiente comando y no necesita una tabla temporal. Funciona para mí en Android Studio.

 db.execSQL("alter table child add column newCol integer REFERENCES parent(parentId)"); 

Primero agregue una columna en la tabla secundaria Cid como int luego alter table con el código siguiente. De esta forma, puede agregar la clave externa Cid como la clave principal de la tabla padre y usarla como la clave externa en la tabla secundaria … espero que lo ayude, ya que es bueno para mí:

 ALTER TABLE [child] ADD CONSTRAINT [CId] FOREIGN KEY ([CId]) REFERENCES [Parent]([CId]) ON DELETE CASCADE ON UPDATE NO ACTION; GO