2009-12-10 22 views
104

Tengo la siguiente tabla:¿Cómo agrego una clave externa a una tabla SQLite existente?

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

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

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

Respuesta

161

No puede.

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

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

SQLite no soporta la varianteADD CONSTRAINT del comando ALTER TABLE (sqlite.org: SQL Features That SQLite Does Not Implement).

Por lo tanto, la única manera de añadir una clave externa en SQLite 3.6.1 es durante CREATE TABLE de la siguiente manera:

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

Por desgracia, tendrá que guardar los datos existentes en una tabla temporal, eliminar la tabla de edad , cree la nueva tabla con la restricción FK, luego copie los datos de la tabla temporal. (sqlite.org - FAQ: Q11)

+19

Creo que es más fácil cambiar el nombre de la tabla anterior, crear la nueva tabla y copiar los datos nuevamente. Luego puede soltar la tabla anterior. – tuinstoel

+0

Sí, eso es más fácil. Solo estaba citando las preguntas frecuentes de sqlite: http://www.sqlite.org/faq.html#q11. De hecho, 'RENAME TO' es una de las pocas variantes' ALTER TABLE' que actualmente es compatible con sqlite 3. –

+3

No debería ser: FOREIGN KEY (parent_id) REFERENCIAS parent (id) Es cierto que Jonathan no lo hizo dar el nombre de la "tabla padre". De hecho, la tabla debe ser nombrada persona, pero ... – igorludi

43

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

En primer lugar, crear la tabla sin el parent_id:

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

Entonces, alterar tabla:

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

Es bueno acostumbrarse a esta secuencia, pero esto no responde a la pregunta real: * Me gustaría agregar la restricción a una existente. * – Wolf

4

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

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

En el cuadro de texto Columnas, haga clic con el botón derecho en el último nombre de columna enumerado para que aparezca 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. En el cuadro Tipo de columna, agregue una coma y la definición

FOREIGN KEY (parent_id) REFERENCES parent(id) 

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

7

Por favor, compruebe https://www.sqlite.org/lang_altertable.html#otheralter

La única alteración esquema de comandos directamente apoyado por SQLite son los comandos "Renombrar mesa" y "Añadir columna" que se muestran arriba. Sin embargo, las aplicaciones pueden realizar otros cambios arbitrarios en el formato de una tabla usando una secuencia de operaciones simple. Los pasos para hacer arbitrarias cambios en el diseño del esquema de alguna mesa X son los siguientes:

  1. Si se habilitan las claves foráneas, los deshabilita el uso de PRAGMA FOREIGN_KEYS = OFF.
  2. Comenzar una transacción.
  3. Recuerde el formato de todos los índices y disparadores asociados con tabla X. Esta información será necesaria en el paso 8 a continuación. Una manera de hacer esto es ejecutar una consulta como la siguiente: SELECCIONAR tipo, sql FROM sqlite_master WHERE tbl_name = 'X'.
  4. Use CREATE TABLE para construir una nueva tabla "new_X" que esté en 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. contenido
  6. de transferencia de X en nueva_matriz_x mediante una declaración como: INSERTAR EN nueva_matriz_x SELECT ... FROM X.
  7. gota de la mesa de edad X: DROP TABLE X.
  8. Cambiar el nombre de nueva_matriz_x a X usando: ALTER TABLE nueva_matriz_x Renombrar para X.
  9. uso creen INDEX y CREATE TRIGGER para reconstruir índices y momentos asociados con la tabla X. Tal vez utilizar el antiguo formato de los disparadores y los índices guardados desde el paso 3 anterior como guía, haciendo cambios según corresponda para la alteración.
  10. Si cualquier punto de vista se refieren a la tabla X de manera que se ve afectado por el cambio esquema, a continuación, colocar los puntos de vista utilizando la vista de eliminar y reconstruir con cualquier condición necesaria para acomodar cambios en el cambio de esquema utilizando CREATE VIEW.
  11. 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.
  12. Confirmar la transacción iniciada en el paso 2.
  13. 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 la información almacenada en la tabla cambie. Entonces el procedimiento completo anterior es apropiado para colocar una columna, cambiando el orden de las columnas, agregando o eliminando una restricción UNIQUE o PRIMARY KEY, agregando restricciones CHECK o FOREIGN KEY o NOT NULL, o cambiando el tipo de datos para una columna, por ejemplo.

-2

Primera añadir una columna en la tabla secundaria Cid como int continuación alter table con el código de abajo. De esta manera usted puede agregar la clave externa Cid como la clave principal de la tabla primaria y utilizarlo como la clave externa en la tabla hijo ... espero que le ayudará, 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 
+1

Esto no es válido en SQLite. También esta es la sintaxis de MS SQL. – StilesCrisis

-1

Usted ¡PODER!

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)"); 
+0

Parece que no leyó la pregunta con cuidado. El problema era agregar una restricción externa solamente, no agregar una columna con una restricción. – Wolf

0

Sí, puede, sin agregar una nueva columna. Usted tiene que tener cuidado de hacerlo correctamente para evitar la corrupción de la base de datos, por lo que debe volver completamente a su base de datos antes de intentar esto:

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 lo que el SQL definición es antes de hacer cualquier cambio:

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

Si se utiliza el método replace(), puede que le resulte útil, antes de ejecutar, probar primero su comando replace() ejecutando:

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