Comment renommer une colonne dans une table de base de données SQLite?

296

J'aurais besoin de renommer quelques colonnes dans certaines tables d'une base de données SQLite. Je sais qu'une question similaire a été posée sur stackoverflow précédemment, mais c'était pour SQL en général, et le cas de SQLite n'a pas été mentionné.

D'après la documentation SQLite pour ALTER TABLE , je suppose qu'il n'est pas possible de faire une telle chose "facilement" (c'est-à-dire une seule instruction ALTER TABLE).

Je me demandais si quelqu'un connaissait une façon générique SQL de faire une telle chose avec SQLite.

joce
la source
Vous pouvez le faire en utilisant le navigateur db pour sqlite assez facilement
Matt G
1
Veuillez considérer de marquer cette réponse comme acceptée stackoverflow.com/a/52346199/124486
Evan Carroll

Réponses:

66

Cela vient d'être corrigé avec 2018-09-15 (3.25.0)

Améliorations de la ALTER TABLEcommande:

  • Ajoutez la prise en charge du changement de nom des colonnes d'une table à l'aide d'une ALTER TABLEtable RENAME COLUMN oldname TO newname.
  • Correction de la fonction de changement de nom de table afin qu'elle mette également à jour les références à la table renommée dans les déclencheurs et les vues.

Vous pouvez trouver la nouvelle syntaxe documentée sous ALTER TABLE

La RENAME COLUMN TOsyntaxe change le nom de colonne de la table nom-table en nouveau-nom-colonne. Le nom de la colonne est modifié à la fois dans la définition de table elle-même et également dans tous les index, déclencheurs et vues faisant référence à la colonne. Si le changement de nom de colonne entraîne une ambiguïté sémantique dans un déclencheur ou une vue, l' RENAME COLUMNéchec avec une erreur et aucun changement n'est appliqué.

entrez la description de l'image ici Source de l'image: https://www.sqlite.org/images/syntax/alter-table-stmt.gif

Exemple:

CREATE TABLE tab AS SELECT 1 AS c;

SELECT * FROM tab;

ALTER TABLE tab RENAME COLUMN c to c_new;

SELECT * FROM tab;

Démo db-fiddle.com


Prise en charge Android

Au moment de l'écriture, l'API d'Android 27 utilise la version 3.19 du package SQLite .

Sur la base de la version actuelle qu'Android utilise et que cette mise à jour arrive dans la version 3.25.0 de SQLite, je dirais que vous avez un peu d'attente (environ API 33) avant que la prise en charge de cela ne soit ajoutée à Android.

Et, même dans ce cas, si vous devez prendre en charge des versions antérieures à l'API 33, vous ne pourrez pas l'utiliser.

Lukasz Szozda
la source
8
J'implémente pour une migration Android et malheureusement IntelliJ affiche un avertissement qu'il ne s'agit pas d'une commande SQL valide. database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount"). COLUM est surligné en rouge et indique TO attendu, a obtenu 'COLUMN' . Malheureusement, Android est toujours sur SQLite version 3.19, c'est pourquoi cela ne fonctionne pas pour moi.
Adam Hurwitz
1
édité: J'ai trouvé sur system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1 , que le 1.0.109.x) utilise réellement SQLite 3.24 et System.Data.SQLite l'utilisation de SQLite 3.25 devrait être relâchée ce mois-ci.
rychlmoj
1
Pour info, malheureusement, cela n'a pas encore été implémenté par la bibliothèque SQLite d' Android . J'espère qu'ils seront bientôt mis à jour.
Adam Hurwitz
3
J'ai ajouté une section pour le support Android pour empêcher les autres de réaliser leurs espoirs. Sur la base de l'utilisation actuelle d'Android 27 de SQLite 3.19, nous devrons attendre environ l'API 33 avant d'ajouter cette fonctionnalité à Android, et même alors, elle ne sera prise en charge que sur les dernières versions. Soupir.
Joshua Pinter
1
@JoshuaPinter Merci d'avoir étendu ma réponse.
Lukasz Szozda
448

Supposons que vous ayez une table et que vous deviez renommer "colb" en "col_b":

Vous renommez d'abord l'ancienne table:

ALTER TABLE orig_table_name RENAME TO tmp_table_name;

Créez ensuite la nouvelle table, basée sur l'ancienne table mais avec le nom de colonne mis à jour:

CREATE TABLE orig_table_name (
  col_a INT
, col_b INT
);

Copiez ensuite le contenu en face du tableau d'origine.

INSERT INTO orig_table_name(col_a, col_b)
SELECT col_a, colb
FROM tmp_table_name;

Enfin, laissez tomber l'ancienne table.

DROP TABLE tmp_table_name;

Envelopper tout cela dans un BEGIN TRANSACTION;et COMMIT;c'est aussi probablement une bonne idée.

Evan
la source
51
Et n'oubliez pas vos indices.
Tom Mayfield
11
Très important, l'exemple de code ci-dessus manque une transaction. Vous devez envelopper le tout dans un BEGIN / END (ou ROLLBACK) pour vous assurer que le changement de nom se termine avec succès ou pas du tout.
Roger Binns
4
Quiconque souhaite le faire dans Android peut implémenter des transactions à l'aide de SQLiteDatabase.beginTransaction ()
bmaupin
7
Il n'y a rien dans le code de la réponse qui copie les index. Créer une table vide et y placer des données copie uniquement la structure et les données. Si vous voulez des métadonnées (index, clés étrangères, contraintes, etc.), vous devez également émettre des instructions pour les créer sur la table remplacée.
Tom Mayfield
17
La .schemacommande SQLite est pratique pour afficher l' CREATE TABLEinstruction qui crée la table existante. Vous pouvez prendre sa sortie, la modifier selon vos besoins et l'exécuter pour créer la nouvelle table. Cette commande affiche également les CREATE INDEXcommandes nécessaires pour créer les indices, qui devraient couvrir les préoccupations de Thomas. Bien sûr, assurez-vous d'exécuter cette commande avant de modifier quoi que ce soit.
Mike DeSimone
56

En fouillant, j'ai trouvé cet outil graphique multiplateforme (Linux | Mac | Windows) appelé DB Browser for SQLite qui permet en fait de renommer des colonnes d'une manière très conviviale!

Modifier | Modifier le tableau | Sélectionnez le tableau | Modifier le champ. Cliquez, cliquez! Voila!

Cependant, si quelqu'un veut partager une manière programmatique de le faire, je serais heureux de savoir!

joce
la source
1
Il existe également un module complémentaire Firefox qui fait la même chose . Faites un clic droit sur la colonne que vous souhaitez renommer et sélectionnez "Modifier la colonne".
Jacob Hacker
1
Même dans openSUSE, il est disponible sous forme de package: software.opensuse.org/package/sqlitebrowser
C'est bizarre qu'il ait autant de votes. Nous parlons ici de programmation (code). Pourquoi avez-vous même posté cette réponse ici?
user25
2
Il n'y a aucune mention de la façon de faire cela avec du code dans ma question. Je voulais juste savoir comment renommer une colonne dans une base de données SQLite.
joce
@joce je t'aime !!! (comme un frère) m'a fait changer de domaine, le tour est joué. J'avais exporté une table MS Access vers SQLite et l'un des champs avait un chiffre devant: 3YearLetterSent. Visual Studio a créé la classe à partir de la table mais s'est étouffé avec le chiffre "3" à l'avant du nom du champ. Je le sais, je ne regardais tout simplement pas.
JustJohn
53

S'il est vrai qu'il n'y a pas d'ALTER COLUMN, si vous souhaitez uniquement renommer la colonne, supprimer la contrainte NOT NULL ou modifier le type de données, vous pouvez utiliser l'ensemble de commandes suivant:

Remarque: Ces commandes ont le potentiel de corrompre votre base de données, alors assurez-vous d'avoir une sauvegarde

PRAGMA writable_schema = 1;
UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
PRAGMA writable_schema = 0;

Vous devrez soit fermer et rouvrir votre connexion, soit vider la base de données pour recharger les modifications dans le schéma.

Par exemple:

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> create table BOOKS ( title TEXT NOT NULL, publication_date TEXT NOT NULL);  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
Error: BOOKS.publication_date may not be NULL  
sqlite> PRAGMA writable_schema = 1; 
sqlite> UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';  
sqlite> PRAGMA writable_schema = 0;  
sqlite> .q  

Y:\> sqlite3 booktest  
SQLite version 3.7.4  
Enter ".help" for instructions  
Enter SQL statements terminated with a ";"  
sqlite> insert into BOOKS VALUES ("NULLTEST",null);  
sqlite> .q  

RÉFÉRENCES SUIVENT:


pragma writable_schema
Lorsque ce pragma est activé, les tables SQLITE_MASTER dans lesquelles la base de données peut être modifiée à l'aide des instructions UPDATE, INSERT et DELETE ordinaires. Attention: une mauvaise utilisation de ce pragma peut facilement entraîner un fichier de base de données corrompu.

alter table
SQLite prend en charge un sous-ensemble limité de ALTER TABLE. La commande ALTER TABLE dans SQLite permet à l'utilisateur de renommer une table ou d'ajouter une nouvelle colonne à une table existante. Il n'est pas possible de renommer une colonne, de supprimer une colonne ou d'ajouter ou de supprimer des contraintes d'une table.

ALTER TABLE SYNTAX

Noé
la source
3
Dangereux, mais toujours probablement la réponse la plus simple imo.
Tek
2
Oui extrêmement rapide - Dangereux signifie seulement "Assurez-vous d'avoir une sauvegarde en premier"
Noah
6
Le format de fichier sqlite est très simple et c'est pourquoi cette opération est valide. Le format de fichier ne contient que deux ensembles d'informations sur une table: la commande CREATE TABLE réelle en texte brut et les lignes, dont les valeurs apparaissent dans l'ordre des champs de la commande CREATE. Ce qui signifie que le code sqlite ouvre la base de données, il analyse chaque commande CREATE et crée dynamiquement ses informations de colonne en mémoire. Ainsi, toute commande qui modifie la commande CREATE d'une manière qui aboutit au même nombre de colonnes fonctionnera, même si vous changez leur type ou leurs contraintes.
Thomas Tempelmann
3
@ThomasTempelmann Cependant, l'ajout de contraintes qui ne sont pas remplies par l'ensemble de données entraînera des problèmes car le planificateur de requêtes suppose que les contraintes sont respectées.
fuz
2
@ThomasTempelmann Supprimer les contraintes c'est toujours bien. L'ajout de contraintes est correct si la contrainte est satisfaite par toutes les lignes mais vous devez certainement vérifier.
2016
18

Récemment, j'ai dû le faire dans SQLite3 avec une table nommée points avec l' id de colunms , lon, lat . Erroneusly, lorsque la table a été importée, les valeurs de latitude étaient stockées dans la colonne lon et vice versa, donc une solution évidente serait de renommer ces colonnes. L'astuce était donc:

create table points_tmp as select id, lon as lat, lat as lon from points;
drop table points;
alter table points_tmp rename to points;

J'espère que cela vous sera utile!

aizquier
la source
Cette méthode ne copie pas la valeur PK de manière appropriée et crée automatiquement la colonne rowid masquée. Pas forcément un problème mais je voulais le souligner car c'est devenu un problème pour moi.
TPoschel
4
Ne serait-il pas plus facile de faire "UPDATE points SET lon = lat, lat = lon;"?
kstep
1
Cette réponse fait le processus dans le bon ordre. Créez d'abord la table temporaire et remplissez-la, puis détruisez l'original .
Xeoncross
14

Citant la documentation sqlite :

SQLite prend en charge un sous-ensemble limité de ALTER TABLE. La commande ALTER TABLE dans SQLite permet à l'utilisateur de renommer une table ou d'ajouter une nouvelle colonne à une table existante. Il n'est pas possible de renommer une colonne, de supprimer une colonne ou d'ajouter ou de supprimer des contraintes d'une table.

Ce que vous pouvez bien sûr faire, c'est créer un nouveau tableau avec la nouvelle disposition SELECT * FROM old_tableet remplir le nouveau tableau avec les valeurs que vous recevrez.

Elazar Leibovich
la source
7

Tout d'abord, c'est une de ces choses qui me gifle avec surprise: renommer une colonne nécessite de créer une table entièrement nouvelle et de copier les données de l'ancienne table vers la nouvelle table ...

L'interface graphique sur laquelle j'ai atterri pour effectuer des opérations SQLite est Base . Il a une fenêtre de journal astucieuse qui montre toutes les commandes qui ont été exécutées. Le fait de renommer une colonne via Base remplit la fenêtre de journal avec les commandes nécessaires:

Fenêtre du journal de base

Ceux-ci peuvent ensuite être facilement copiés et collés là où vous en avez besoin. Pour moi, c'est dans un fichier de migration ActiveAndroid . Une bonne touche, également, est que les données copiées incluent uniquement les commandes SQLite, pas les horodatages, etc.

Espérons que cela fera gagner du temps à certaines personnes.

Joshua Pinter
la source
Pour votre information, si vous êtes utilisez ActiveAndroid , vous pouvez omettre BEGIN TRANSACTION;et COMMIT;lignes, comme les poignées ActiveAndroid que par lui - même.
Joshua Pinter
6

CAS 1: SQLite 3.25.0+

Seule la version 3.25.0 de SQLite prend en charge le changement de nom des colonnes. Si votre appareil répond à cette exigence, les choses sont assez simples. La requête ci-dessous résoudrait votre problème:

ALTER TABLE "MyTable" RENAME COLUMN "OldColumn" TO "NewColumn";

CAS 2: SQLite Versions antérieures

Vous devez suivre une approche différente pour obtenir le résultat qui pourrait être un peu délicat

Par exemple, si vous avez une table comme celle-ci:

CREATE TABLE student(Name TEXT, Department TEXT, Location TEXT)

Et si vous souhaitez changer le nom de la colonne Location

Étape 1: renommer la table d'origine:

ALTER TABLE student RENAME TO student_temp;

Étape 2: Créez maintenant une nouvelle table studentavec le nom de colonne correct:

CREATE TABLE student(Name TEXT, Department TEXT, Address TEXT)

Étape 3: copiez les données de la table d'origine dans la nouvelle table:

INSERT INTO student(Name, Department, Address) SELECT Name, Department, Location FROM student_temp;

Remarque: La commande ci-dessus doit être composée d'une seule ligne.

Étape 4: déposez la table d'origine:

DROP TABLE student_temp;

Avec ces quatre étapes, vous pouvez modifier manuellement n'importe quelle table SQLite. Gardez à l'esprit que vous devrez également recréer tous les index, visualiseurs ou déclencheurs sur la nouvelle table.

Febin Mathew
la source
1
Comment mettre à niveau la version de la base de données sqllite vers 3.29.0 dans Android Studio, j'utilise le niveau 28 de l'API.
Nathani Software
La version SQLite est définie par l'appareil sur lequel l'application fonctionne. Cela dépend de l'appareil.
Febin Mathew
1
Pour les personnes utilisant l'ancien sqlite, les quatre étapes ci-dessus sont déconseillées. Voir la section "Caution" sur sqlite.org/lang_altertable.html .
Jeff
3

changer la colonne de table <id> en <_id>

 String LastId = "id";

    database.execSQL("ALTER TABLE " + PhraseContract.TABLE_NAME + " RENAME TO " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("CREATE TABLE " + PhraseContract.TABLE_NAME
    +"("
            + PhraseContract.COLUMN_ID + " INTEGER PRIMARY KEY,"
            + PhraseContract.COLUMN_PHRASE + " text ,"
            + PhraseContract.COLUMN_ORDER  + " text ,"
            + PhraseContract.COLUMN_FROM_A_LANG + " text"
    +")"
    );
    database.execSQL("INSERT INTO " +
            PhraseContract.TABLE_NAME + "("+ PhraseContract.COLUMN_ID +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +")" +
            " SELECT " + LastId +" , "+ PhraseContract.COLUMN_PHRASE + " , "+ PhraseContract.COLUMN_ORDER +" , "+ PhraseContract.COLUMN_FROM_A_LANG +
            " FROM " + PhraseContract.TABLE_NAME + "old");
    database.execSQL("DROP TABLE " + PhraseContract.TABLE_NAME + "old");
Vahe Gharibyan
la source
3

Créez une nouvelle colonne avec le nom de colonne souhaité: COLNew.

ALTER TABLE {tableName} ADD COLUMN COLNew {type};

Copiez le contenu de l'ancienne colonne COLOld dans la nouvelle colonne COLNew.

INSERT INTO {tableName} (COLNew) SELECT {COLOld} FROM {tableName}

Remarque: les parenthèses sont nécessaires dans la ligne ci-dessus.

Anthony Ebert
la source
2

Comme mentionné précédemment, il existe un outil SQLite Database Browser, qui fait cela. Lyckily, cet outil conserve un journal de toutes les opérations effectuées par l'utilisateur ou l'application. En faisant cela une fois et en consultant le journal des applications, vous verrez le code impliqué. Copiez la requête et collez-la si nécessaire. A travaillé pour moi. J'espère que cela t'aides

Chris Lytridis
la source
2

De la documentation officielle

Une procédure plus simple et plus rapide peut éventuellement être utilisée pour certaines modifications qui n'affectent en rien le contenu du disque. La procédure plus simple suivante est appropriée pour supprimer les contraintes CHECK ou FOREIGN KEY ou NOT NULL, renommer les colonnes ou ajouter ou supprimer ou modifier les valeurs par défaut sur une colonne.

  1. Démarrez une transaction.

  2. Exécutez PRAGMA schema_version pour déterminer le numéro de version du schéma actuel. Ce numéro sera nécessaire pour l'étape 6 ci-dessous.

  3. Activez l'édition de schéma à l'aide de PRAGMA writable_schema = ON.

  4. Exécutez une instruction UPDATE pour modifier la définition de la table X dans la table sqlite_master: UPDATE sqlite_master SET sql = ... WHERE type = 'table' AND name = 'X';

    Attention: une modification de la table sqlite_master comme celle-ci rendra la base de données corrompue et illisible si la modification contient une erreur de syntaxe. Il est suggéré de tester soigneusement l'instruction UPDATE sur une base de données vierge distincte avant de l'utiliser sur une base de données contenant des données importantes.

  5. Si la modification de la table X affecte également d'autres tables ou les index ou déclencheurs sont des vues dans le schéma, exécutez les instructions UPDATE pour modifier ces autres index et vues de tables également. Par exemple, si le nom d'une colonne change, toutes les contraintes, déclencheurs, index et vues FOREIGN KEY qui font référence à cette colonne doivent être modifiés.

    Attention: Encore une fois, apporter des modifications à la table sqlite_master comme celle-ci rendra la base de données corrompue et illisible si la modification contient une erreur. Testez soigneusement toute cette procédure sur une base de données de test distincte avant de l'utiliser sur une base de données contenant des données importantes et / ou effectuez des copies de sauvegarde des bases de données importantes avant d'exécuter cette procédure.

  6. Incrémentez le numéro de version de schéma à l'aide de PRAGMA schema_version = X où X est un de plus que l'ancien numéro de version de schéma trouvé à l'étape 2 ci-dessus.

  7. Désactivez l'édition de schéma à l'aide de PRAGMA writable_schema = OFF.

  8. (Facultatif) Exécutez PRAGMA Integrity_check pour vérifier que les modifications de schéma n'ont pas endommagé la base de données.

  9. Validez la transaction commencée à l'étape 1 ci-dessus.

Mohammad Yahia
la source
PRAGMA Integrity_check ne détecte aucune erreur dans le schéma.
Graymatter
et quel est le problème avec ça?
Mohammad Yahia
1

Une option, si vous avez besoin de le faire à la rigueur, et si votre colonne initiale a été créée avec une valeur par défaut, est de créer la nouvelle colonne que vous voulez, de copier le contenu dessus et, fondamentalement, "d'abandonner" l'ancienne colonne (elle reste présent, mais vous ne l'utilisez pas / ne le mettez pas à jour, etc.)

ex:

alter table TABLE_NAME ADD COLUMN new_column_name TYPE NOT NULL DEFAULT '';
update TABLE_NAME set new_column_name = old_column_name;
update TABLE_NAME set old_column_name = ''; -- abandon old column, basically

Cela laisse une colonne (et si elle a été créée avec NOT NULL mais sans valeur par défaut, les insertions futures qui l'ignorent pourraient échouer), mais s'il ne s'agit que d'une table jetable, les compromis peuvent être acceptables. Sinon, utilisez l'une des autres réponses mentionnées ici ou une base de données différente qui permet de renommer les colonnes.

rogerdpack
la source
-1

Depuis la version 2018-09-15 (3.25.0), sqlite prend en charge le changement de nom des colonnes

https://sqlite.org/changes.html

RusAlex
la source
-3

sqlite3 yourdb .dump> /tmp/db.txt
modifier /tmp/db.txt changer le nom de la colonne dans Créer une ligne
sqlite2 yourdb2 </tmp/db.txt
mv / déplacer yourdb2 yourdb

H Bosch
la source
3
votre réponse ne fournit aucune information, un tas de code / instructions crache sans aucune information supplémentaire sur les raisons pour lesquelles vous pensez que cela fonctionnera ou ce qui devrait se produire si vous l'exécutez
RGLSV