web-dev-qa-db-fra.com

Comment ajouter une clé étrangère à une table SQLite existante?

J'ai le tableau suivant:

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

Comment ajouter une contrainte de clé étrangère sur parent_id? Supposons que les clés étrangères sont activées.

La plupart des exemples supposent que vous créez la table - j'aimerais ajouter la contrainte à une contrainte existante.

116
Dane O'Connor

Vous ne pouvez pas.

Bien que la syntaxe SQL-92 pour ajouter une clé étrangère à votre table soit la suivante:

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

SQLite ne supporte pas le ADD CONSTRAINT variante du ALTER TABLE commande ( sqlite.org: fonctionnalités SQL non implémentées par SQLite ).

Par conséquent, la seule façon d'ajouter une clé étrangère dans sqlite 3.6.1 est pendant CREATE TABLE comme suit:

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

Malheureusement, vous devrez enregistrer les données existantes dans une table temporaire, supprimer l'ancienne table, créer la nouvelle table avec la contrainte FK, puis copier les données à partir de la table temporaire. ( sqlite.org - FAQ: Q11 )

184
Daniel Vassallo

Vous pouvez ajouter la contrainte si vous modifiez table et ajoutez la colonne qui utilise la contrainte.

Tout d'abord, créez une table sans le parent_id:

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

Ensuite, modifiez le tableau:

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

Veuillez vérifier https://www.sqlite.org/lang_altertable.html#otheralter

Les seules commandes de modification de schéma directement prises en charge par SQLite sont les commandes "renommer la table" et "ajouter une colonne" présentées ci-dessus. Toutefois, les applications peuvent apporter d'autres modifications arbitraires au format d'une table à l'aide d'une simple séquence d'opérations. Les étapes pour apporter des modifications arbitraires à la conception de schéma de certaines tables X sont les suivantes:

  1. Si les contraintes de clé étrangère sont activées, désactivez-les à l'aide de PRAGMA foreign_keys = OFF.
  2. Lancer une transaction.
  3. N'oubliez pas le format de tous les index et déclencheurs associés à la table X. Ces informations seront nécessaires à l'étape 8 ci-dessous. Une façon de procéder consiste à exécuter une requête du type suivant: type SELECT, sql FROM sqlite_master WHERE nom_table = 'X'.
  4. Utilisez CREATE TABLE pour construire une nouvelle table "new_X" au format souhaité de la table X. Assurez-vous que le nom "new_X" n'entre pas en conflit avec un nom de table existant, bien sûr.
  5. Transférez le contenu de X dans new_X à l'aide d'une instruction telle que: INSERT INTO new_X SELECT ... FROM X.
  6. Supprimez l'ancienne table X: DROP TABLE X.
  7. Changez le nom de new_X en X en utilisant: ALTER TABLE new_X RENAME TO X.
  8. Utilisez CREATE INDEX et CREATE TRIGGER pour reconstruire les index et les déclencheurs associés à la table X. Utilisez peut-être l'ancien format des déclencheurs et des index enregistrés à l'étape 3 ci-dessus comme guide, en apportant les modifications appropriées à la modification.
  9. Si des vues font référence à la table X d'une manière affectée par le changement de schéma, supprimez-les à l'aide de DROP VIEW et recréez-les avec toutes les modifications nécessaires pour prendre en compte le changement de schéma à l'aide de CREATE VIEW.
  10. Si les contraintes de clé étrangère ont été activées à l'origine, exécutez PRAGMA foreign_key_check pour vérifier que le changement de schéma ne respecte pas les contraintes de clé étrangère.
  11. Commettez la transaction commencée à l'étape 2.
  12. Si les contraintes de clés étrangères étaient initialement activées, réactivez-les maintenant.

La procédure ci-dessus est complètement générale et fonctionnera même si le changement de schéma entraîne la modification des informations stockées dans la table. La procédure complète ci-dessus convient donc pour supprimer une colonne, modifier l’ordre des colonnes, ajouter ou supprimer une contrainte UNIQUE ou PRIMARY KEY, ajouter des contraintes CHECK ou FOREIGN KEY ou NOT NULL, ou modifier le type de données d’une colonne, par exemple.

8
situee

Oui, vous pouvez, sans ajouter de nouvelle colonne. Vous devez faire attention à le faire correctement afin d'éviter de corrompre la base de données. Vous devez donc sauvegarder complètement votre base de données avant de l'essayer.

pour votre exemple spécifique:

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

ou plus généralement:

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;

Quoi qu'il en soit, vous voudrez probablement d'abord voir quelle est la définition SQL avant d'apporter des modifications:

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

Si vous utilisez l'approche replace (), vous trouverez peut-être utile, avant de l'exécuter, de tester d'abord votre commande replace () en exécutant:

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

Si vous utilisez le complément Firefox, sqlite-manager, vous pouvez effectuer les opérations suivantes:

Au lieu de supprimer et de créer à nouveau la table, vous pouvez simplement la modifier comme ceci.

Dans la zone de texte Colonnes, cliquez avec le bouton droit sur le dernier nom de colonne répertorié pour afficher le menu contextuel, puis sélectionnez Modifier la colonne. Notez que si la dernière colonne de la définition de TABLE est la PRIMARY KEY, il faudra d'abord ajouter une nouvelle colonne, puis éditer le type de colonne de la nouvelle colonne afin d'ajouter la définition FOREIGN KEY. Dans la zone Type de colonne, ajoutez une virgule et le

FOREIGN KEY (parent_id) REFERENCES parent(id)

définition après type de données. Cliquez sur le bouton Modifier, puis sur le bouton Oui de la boîte de dialogue Opération dangereuse.

Référence: Sqlite Manager

3
Baso

Vous pouvez essayer ceci:

ALTER TABLE [Child] ADD COLUMN column_name INTEGER REFERENCES parent_table_name(column_id);
1
Jamshy EK