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 - je voudrais ajouter la contrainte à une existante.

111
demandé sur Wolf 2009-12-11 02:22:50

7 réponses

vous ne pouvez pas.

bien que la syntaxe SQL-92 pour ajouter une clé étrangère à votre table serait comme suit:

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

SQLite ne supporte pas les le ADD CONSTRAINT variante de la "151930920 de la commande" ( sqlite.org: SQL Caractéristiques Que SQLite Ne Pas mettre en Œuvre ).

par conséquent, la seule façon d'ajouter une clé étrangère en 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 sauvegarder les données existantes dans une table temporaire, laisser tomber l'ancienne table, créer la nouvelle table avec la contrainte FK, puis recopier les données à partir de la table temporaire. ( sqlite.org -FAQ: Q11 )

172
répondu Daniel Vassallo 2012-09-25 05:13:09

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

tout d'abord, créer la table sans le parent_id:

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

puis, modifier la table:

ALTER TABLE child ADD COLUMN parent_id INTEGER REFERENCES parent(id);
47
répondu Jorge Novaes 2014-05-09 21:20:50

s'il vous Plaît cochez la case https://www.sqlite.org/lang_altertable.html#otheralter

les seules commandes de modification de schéma directement supportées par SQLite sont les les commandes" rename table "et" add column " ci-dessus. Cependant, les applications peuvent apporter d'autres changements arbitraires au format d'une table en utilisant une simple séquence d'opérations. Les mesures pour rendre arbitraire les modifications apportées au schéma de certains tableaux X sont les suivantes::

  1. si les contraintes de clé étrangère sont activées, les désactiver en utilisant PRAGMA foreign_keys = OFF.
  2. lancer une transaction.
  3. se rappeler le format de tous les index et déclencheurs associés à tableau X. Cette information sera nécessaire à l'étape 8 ci-dessous. Une façon de faire ceci est d'exécuter une requête comme suit: SELECT type, sql FROM sqlite_master où tbl_name= 'X'.
  4. utiliser créer le tableau pour construire une nouvelle table "new_X" qui est dans le révision souhaitée du format du tableau X. assurez-vous que le nom "new_X" n'entre pas en conflit avec un nom de table existant, bien sûr.
  5. transférer le contenu de X vers new_X en utilisant une instruction du type: INSERT Dans new_X SELECT ... De X.
  6. Supprimer l'ancien tableau X: supprimer le tableau X.
  7. changer le nom de new_X en X en utilisant: ALTER TABLE new_X renommer en X.
  8. utiliser créer INDEX et créer le déclencheur pour reconstruire les index et déclencheurs associés à la table X. peut-être utiliser l'ancien format de la déclencheurs et Index sauvegardés de l'étape 3 ci-dessus comme un guide, faisant les modifications appropriées à la modification.
  9. si des vues se réfèrent au tableau X d'une manière qui est affectée par le changer de schéma, puis laisser tomber ces vues en utilisant DROP VIEW et recréer les modifications nécessaires pour s'adapter au schéma changer en utilisant CREATE VIEW.
  10. si les contraintes de clé étrangère étaient initialement permises, alors lancer PRAGMA etranger_key_check pour vérifier que le changement de schéma ne s'est pas brisé toute contrainte de clé étrangère.
  11. valider la transaction a commencé à l'étape 2.
  12. si les contraintes de clés étrangères étaient à l'origine activées, les rendre maintenant.

la procédure ci-dessus est complètement générale et fonctionnera même si le changement de schéma modifie l'information stockée dans la table. Si la procédure complète ci-dessus est appropriée pour faire tomber une colonne, modification de l'ordre des colonnes, ajout ou suppression d'une contrainte UNIQUE ou clé primaire, en ajoutant des contraintes CHECK ou clé étrangère ou non NULL, ou de changer le type de données pour une colonne, par exemple.

8
répondu situee 2015-03-05 02:38:19

si vous utilisez le Firefox add-on sqlite-manager vous pouvez faire ce qui suit:

au lieu de laisser tomber et de créer la table à nouveau, on peut juste la modifier comme ceci.

dans la zone de texte des colonnes, cliquez avec le bouton droit de la souris sur le nom de la dernière colonne pour afficher le menu contextuel et sélectionner Modifier la colonne. Notez que si la dernière colonne dans la définition de la TABLE est la clé primaire alors il sera nécessaire d'ajouter une nouvelle colonne puis éditez le type de colonne de la nouvelle colonne afin d'ajouter la définition de clé étrangère. Dans la case du type de colonne , ajouter une virgule et le

FOREIGN KEY (parent_id) REFERENCES parent(id)

définition après type de données. Cliquez sur le bouton Changer, puis cliquez sur le bouton Oui dans la boîte de dialogue Dangerous Operation.

référence: Sqlite Manager

3
répondu Baso 2015-02-08 21:27:27

Oui, vous pouvez, sans ajouter une nouvelle colonne. Vous devez être prudent de le faire correctement afin d'éviter de corrompre la base de données, de sorte que vous devriez complètement sauvegarder votre base de données avant d'essayer cela.

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;

de toute façon, vous voudrez probablement d'abord voir ce que la définition SQL est avant de faire des changements:

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

si vous utilisez l'approche replace (), vous pouvez trouver utile, avant l'exécution, de tester d'abord votre commande replace() en lançant:

select update(sql, ...) from SQLITE_MASTER where name = 'child' and type = 'table';
1
répondu mwag 2018-05-21 06:34:20

vous pouvez!

Essayez la commande suivante et vous n'avez pas besoin d'une table temporaire. Ça marche pour moi dans Android Studio.

db.execSQL("alter table child add column newCol integer REFERENCES parent(parentId)");
-1
répondu saeed khalafinejad 2016-11-20 07:05:12

ajouter D'abord une colonne dans la table pour enfants Cid comme int puis alter table avec le code ci-dessous. De cette façon, vous pouvez ajouter la clé étrangère Cid comme la clé primaire de la table parent et l'utiliser comme clé étrangère dans la table enfant ... j'espère qu'il vous aidera car il est bon pour moi:

ALTER TABLE [child] 
  ADD CONSTRAINT [CId] 
  FOREIGN KEY ([CId]) 
  REFERENCES [Parent]([CId]) 
  ON DELETE CASCADE ON UPDATE NO ACTION;
GO
-2
répondu Tariq Nawaz Khan 2016-07-25 18:22:29