Come rinominare una colonna in una tabella del database SQLite?


296

Avrei bisogno di rinominare alcune colonne in alcune tabelle in un database SQLite. So che una domanda simile è stata posta in precedenza su StackOverflow, ma era per SQL in generale e il caso di SQLite non è stato menzionato.

Dalla documentazione di SQLite per ALTER TABLE , ho capito che non è possibile fare una cosa del genere "facilmente" (cioè una singola istruzione ALTER TABLE).

Mi chiedevo che qualcuno sapesse di un modo SQL generico di fare una cosa del genere con SQLite.


Puoi farlo usando il browser db per sqlite abbastanza facilmente
Matt G

1
Si prega di considerare di contrassegnare questa risposta come accettata stackoverflow.com/a/52346199/124486
Evan Carroll

Risposte:


66

Questo problema è stato appena risolto con il 15-09-2018 (3.25.0)

Migliora il ALTER TABLEcomando:

  • Aggiungi il supporto per rinominare le colonne all'interno di una tabella usando ALTER TABLEtable RENAME COLUMN oldname TO newname.
  • Correggi la funzionalità di ridenominazione della tabella in modo che aggiorni anche i riferimenti alla tabella rinominata nei trigger e nelle viste.

È possibile trovare la nuova sintassi documentata in ALTER TABLE

La RENAME COLUMN TOsintassi cambia il nome-colonna del nome tabella-tabella in nome-nuova-colonna. Il nome della colonna viene modificato sia all'interno della definizione della tabella stessa, sia all'interno di tutti gli indici, i trigger e le viste che fanno riferimento alla colonna. Se la modifica del nome della colonna comporterebbe un'ambiguità semantica in un trigger o in una vista, la RENAME COLUMNmancata riuscita con un errore e nessuna modifica viene applicata.

inserisci qui la descrizione dell'immagine Fonte immagine: https://www.sqlite.org/images/syntax/alter-table-stmt.gif

Esempio:

CREATE TABLE tab AS SELECT 1 AS c;

SELECT * FROM tab;

ALTER TABLE tab RENAME COLUMN c to c_new;

SELECT * FROM tab;

db-fiddle.com demo


Supporto Android

Al momento della scrittura, l'API 27 di Android utilizza il pacchetto SQLite versione 3.19 .

In base alla versione corrente utilizzata da Android e che questo aggiornamento arriverà nella versione 3.25.0 di SQLite, direi che hai un po 'di attesa (circa API 33) prima che il supporto per questo venga aggiunto ad Android.

E anche in questo caso, se è necessario supportare versioni precedenti all'API 33, non sarà possibile utilizzarlo.


8
Sto implementando una migrazione per Android e sfortunatamente IntelliJ mostra un avviso che non è un comando SQL valido. database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount"). COLUM è illuminato in rosso e dice TO previsto, ha ottenuto "COLONNA" . Sfortunatamente Android è ancora su SQLite versione 3.19, motivo per cui questo non funziona per me.
Adam Hurwitz,

1
modificato: ho scoperto su system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1 , che 1.0.109.x) utilizza effettivamente SQLite 3.24 e System.Data.SQLite l'utilizzo di SQLite 3.25 è programmato per essere rilasato questo mese.
rychlmoj,

1
Cordiali saluti, purtroppo questo non è ancora stato implementato dalla libreria SQLite di Android . Spero che si aggiornino presto.
Adam Hurwitz, il

3
Ho aggiunto una sezione per il supporto Android per impedire ad altri di sperare. In base all'utilizzo corrente di SQLite 3.19 da parte di Android 27, dovremo attendere fino all'incirca all'API 33 prima che questa funzionalità venga aggiunta ad Android e anche in questo caso sarà supportata solo sulle ultime versioni. Sospiro.
Joshua Pinter,

1
@JoshuaPinter Grazie per aver esteso la mia risposta.
Lukasz Szozda,

448

Supponi di avere una tabella e di dover rinominare "colb" in "col_b":

Prima rinominare la vecchia tabella:

ALTER TABLE orig_table_name RENAME TO tmp_table_name;

Quindi creare la nuova tabella, in base alla tabella precedente ma con il nome di colonna aggiornato:

CREATE TABLE orig_table_name (
  col_a INT
, col_b INT
);

Quindi copia il contenuto dalla tabella originale.

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

Infine, lascia cadere il vecchio tavolo.

DROP TABLE tmp_table_name;

Avvolgere tutto questo in una BEGIN TRANSACTION;ed COMMIT;è probabilmente anche una buona idea.


51
E non dimenticare i tuoi indici.
Tom Mayfield,

11
Molto importante il codice di esempio sopra manca una transazione. Dovresti avvolgere il tutto in un BEGIN / END (o ROLLBACK) per assicurarti che la ridenominazione sia stata completata con successo o per niente.
Roger Binns,

4
Chiunque desideri farlo in Android può implementare transazioni usando SQLiteDatabase.beginTransaction ()
bmaupin

7
Non c'è niente nel codice nella risposta che copia gli indici. La creazione di una tabella vuota e l'inserimento di dati in essa copia solo la struttura e i dati. Se desideri metadati (indici, chiavi esterne, vincoli, ecc.), Devi anche emettere istruzioni per crearli nella tabella sostituita.
Tom Mayfield,

17
Il .schemacomando di SQLite è utile per mostrare l' CREATE TABLEistruzione che rende la tabella esistente. Puoi prendere il suo output, modificarlo secondo necessità ed eseguirlo per creare la nuova tabella. Questo comando mostra anche i CREATE INDEXcomandi necessari per creare gli indici, che dovrebbero coprire le preoccupazioni di Thomas. Naturalmente, assicurati di eseguire questo comando prima di modificare qualsiasi cosa.
Mike DeSimone,

56

Scavando, ho trovato questo strumento grafico multipiattaforma (Linux | Mac | Windows) chiamato DB Browser per SQLite che in realtà consente di rinominare le colonne in un modo molto intuitivo!

Modifica | Modifica tabella | Seleziona tabella | Modifica campo. Fare clic fare clic! Ecco!

Tuttavia, se qualcuno vuole condividere un modo programmatico di farlo, sarei felice di saperlo!


1
C'è anche un componente aggiuntivo di Firefox che fa la stessa cosa , fai clic con il pulsante destro del mouse sulla colonna che desideri rinominare e seleziona "Modifica colonna".
Jacob Hacker,

1
Anche in openSUSE, è disponibile come pacchetto: software.opensuse.org/package/sqlitebrowser

È strano che abbia così tanti voti. Stiamo parlando della programmazione qui (codice). Perché hai postato questa risposta qui?
user25

2
Non c'è menzione di come farlo con il codice nella mia domanda. Volevo solo sapere come rinominare una colonna in un DB SQLite.
giovedì

@joce ti amo !!! (come un fratello) mi ha fatto cambiare campo, voilà. Avevo esportato una tabella MS Access in SQLite e uno dei campi aveva una cifra davanti: 3YearLetterSent. Visual Studio ha creato la classe dalla tabella ma è soffocato sulla cifra "3" nella parte anteriore del nome del campo. Lo so, non stavo proprio guardando.
JustJohn

53

Sebbene sia vero che non esiste ALTER COLUMN, se si desidera solo rinominare la colonna, eliminare il vincolo NOT NULL o modificare il tipo di dati, è possibile utilizzare il seguente set di comandi:

Nota: questi comandi potrebbero danneggiare il database, quindi assicurati di disporre di un backup

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;

Sarà necessario chiudere e riaprire la connessione o svuotare il database per ricaricare le modifiche nello schema.

Per esempio:

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  

SEGUENTI RIFERIMENTI:


pragma writable_schema
Quando questo pragma è attivo, le tabelle SQLITE_MASTER in cui è possibile modificare il database utilizzando le normali istruzioni UPDATE, INSERT e DELETE. Attenzione: l'uso improprio di questo pragma può facilmente provocare un file di database corrotto.

alter table
SQLite supporta un sottoinsieme limitato di ALTER TABLE. Il comando ALTER TABLE in SQLite consente all'utente di rinominare una tabella o di aggiungere una nuova colonna a una tabella esistente. Non è possibile rinominare una colonna, rimuovere una colonna o aggiungere o rimuovere vincoli da una tabella.

SINTASSI ALTER TABLE


3
Pericolosa, ma probabilmente la risposta più immediata imo.
Tek,

2
Sì estremamente veloce - Pericoloso significa solo "Assicurati di avere prima un backup"
Noah

6
Il formato del file sqlite è molto semplice ed è per questo che questa operazione è valida. Il formato del file contiene solo due serie di informazioni su una tabella: il comando CREATE TABLE effettivo come testo normale e le righe, i cui valori vengono visualizzati nell'ordine dei campi dal comando CREATE. Ciò significa che il codice sqlite apre il database, analizza ogni comando CREATE e crea dinamicamente le informazioni sulla colonna in memoria. Pertanto, qualsiasi comando che modifica il comando CREATE in un modo che finisce con lo stesso numero di colonne funzionerà, anche se si modifica il loro tipo o vincoli.
Thomas Tempelmann,

3
@ThomasTempelmann Tuttavia, l'aggiunta di vincoli non soddisfatti dal set di dati genererà problemi poiché il pianificatore di query presuppone che i vincoli siano validi.
fuz,

2
@ThomasTempelmann Rimuovere i vincoli va sempre bene. L'aggiunta di vincoli va bene se il vincolo è soddisfatto da tutte le righe ma sicuramente è necessario verificarlo.
fuz,

18

Recentemente ho dovuto farlo in SQLite3 con una tabella denominata points con id di colonne , lon, lat . Erroneamente, quando la tabella è stata importata, i valori per la latitudine sono stati memorizzati nella colonna lon e viceversa, quindi una soluzione ovvia sarebbe quella di rinominare quelle colonne. Quindi il trucco era:

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;

Spero che ti possa essere utile!


Questo metodo non copia il valore PK in modo appropriato e crea automaticamente la colonna nascosta del rowid. Non necessariamente un problema, ma ho voluto segnalarlo perché è diventato un problema per me.
TPoschel

4
Non sarebbe più facile fare "UPDATE points SET lon = lat, lat = lon;"?
kstep,

1
Questa risposta esegue il processo nell'ORDINE corretto. Per prima cosa crea la tabella temporanea e popolala, quindi distruggi l'originale .
Xeoncross,

14

Citando la documentazione di sqlite :

SQLite supporta un sottoinsieme limitato di ALTER TABLE. Il comando ALTER TABLE in SQLite consente all'utente di rinominare una tabella o di aggiungere una nuova colonna a una tabella esistente. Non è possibile rinominare una colonna, rimuovere una colonna o aggiungere o rimuovere vincoli da una tabella.

Quello che puoi fare ovviamente è, creare una nuova tabella con il nuovo layout SELECT * FROM old_tablee riempire la nuova tabella con i valori che riceverai.


7

Prima di tutto, questa è una di quelle cose che mi sorprende in faccia con sorpresa: la ridenominazione di una colonna richiede la creazione di una tabella completamente nuova e la copia dei dati dalla vecchia tabella alla nuova tabella ...

La GUI su cui sono arrivato per eseguire le operazioni SQLite è Base . Ha una bella finestra di registro che mostra tutti i comandi che sono stati eseguiti. Effettuare una ridenominazione di una colonna tramite Base popola la finestra di registro con i comandi necessari:

Finestra del registro di base

Questi possono quindi essere facilmente copiati e incollati dove potresti averne bisogno. Per me, è in un file di migrazione ActiveAndroid . Un bel tocco, inoltre, è che i dati copiati includono solo i comandi SQLite, non i timestamp, ecc.

Spero che questo risparmi tempo ad alcune persone.


Cordiali saluti, se si sta utilizzando ActiveAndroid , è possibile omettere il BEGIN TRANSACTION;e COMMIT;linee, come le maniglie ActiveAndroid che di per sé.
Joshua Pinter

6

CASO 1: SQLite 3.25.0+

Solo la versione 3.25.0 di SQLite supporta la ridenominazione delle colonne. Se il tuo dispositivo soddisfa questo requisito, le cose sono abbastanza semplici. La query seguente risolverebbe il tuo problema:

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

CASO 2: versioni precedenti di SQLite

Devi seguire un approccio diverso per ottenere il risultato che potrebbe essere un po 'complicato

Ad esempio, se hai una tabella come questa:

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

E se desideri cambiare il nome della colonna Location

Passaggio 1: rinominare la tabella originale:

ALTER TABLE student RENAME TO student_temp;

Passaggio 2: ora crea una nuova tabella studentcon il nome di colonna corretto:

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

Passaggio 3: copiare i dati dalla tabella originale alla nuova tabella:

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

Nota: il comando sopra dovrebbe essere tutto su una riga.

Passaggio 4: rilasciare la tabella originale:

DROP TABLE student_temp;

Con questi quattro passaggi è possibile modificare manualmente qualsiasi tabella SQLite. Tieni presente che dovrai anche ricreare qualsiasi indice, visualizzatore o trigger sulla nuova tabella.


1
Come aggiornare la versione del database sqllite alla 3.29.0 in Android Studio sto usando il livello API 28.
Software Nathani

La versione di SQLite è definita dal dispositivo su cui l'app funziona. Dipende dal dispositivo.
Febin Mathew,

1
Per le persone che usano il vecchio sqlite, i quattro passaggi precedenti sono scoraggiati. Vedi la sezione "Attenzione" su sqlite.org/lang_altertable.html .
Jeff,

3

cambia la colonna della tabella <id> in <_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");

3

Crea una nuova colonna con il nome di colonna desiderato: COLNuovo.

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

Copia il contenuto della vecchia colonna COLOld nella nuova colonna COLNew.

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

Nota: le parentesi sono necessarie nella riga sopra.


2

Come accennato in precedenza, esiste uno strumento SQLite Database Browser, che fa questo. Per fortuna, questo strumento tiene un registro di tutte le operazioni eseguite dall'utente o dall'applicazione. Facendolo una volta e guardando il registro dell'applicazione, vedrai il codice in questione. Copia la query e incolla come richiesto. Ha funzionato per me. Spero che questo ti aiuti


2

Dalla documentazione ufficiale

Una procedura più semplice e veloce può essere facoltativamente utilizzata per alcune modifiche che non influiscono in alcun modo sul contenuto del disco. La seguente procedura più semplice è appropriata per rimuovere i vincoli CHECK o FOREIGN KEY o NOT NULL, rinominare le colonne o aggiungere o rimuovere o modificare i valori predefiniti su una colonna.

  1. Inizia una transazione.

  2. Eseguire PRAGMA schema_version per determinare il numero di versione dello schema corrente. Questo numero sarà necessario per il passaggio 6 di seguito.

  3. Attiva la modifica dello schema usando PRAGMA writable_schema = ON.

  4. Eseguire un'istruzione UPDATE per modificare la definizione della tabella X nella tabella sqlite_master: UPDATE sqlite_master SET sql = ... WHERE type = 'table' AND name = 'X';

    Attenzione: apportare una modifica alla tabella sqlite_master in questo modo renderà il database corrotto e illeggibile se la modifica contiene un errore di sintassi. Si suggerisce di eseguire test accurati dell'istruzione UPDATE su un database vuoto separato prima di utilizzarlo su un database contenente dati importanti.

  5. Se la modifica alla tabella X influisce anche su altre tabelle o indici o trigger sono viste all'interno dello schema, eseguire le istruzioni UPDATE per modificare anche gli altri indici e viste delle tabelle. Ad esempio, se il nome di una colonna cambia, è necessario modificare tutti i vincoli, i trigger, gli indici e le viste FOREIGN KEY che fanno riferimento a quella colonna.

    Attenzione: ancora una volta, apportare modifiche alla tabella sqlite_master in questo modo renderà il database corrotto e illeggibile se la modifica contiene un errore. Testare attentamente l'intera procedura su un database di test separato prima di utilizzarlo su un database contenente dati importanti e / o eseguire copie di backup di database importanti prima di eseguire questa procedura.

  6. Incrementa il numero di versione dello schema usando PRAGMA schema_version = X dove X è uno in più rispetto al vecchio numero di versione dello schema trovato nel passaggio 2 sopra.

  7. Disabilitare la modifica dello schema usando PRAGMA writable_schema = OFF.

  8. (Facoltativo) Eseguire PRAGMA integral_check per verificare che le modifiche allo schema non abbiano danneggiato il database.

  9. Conferma la transazione avviata al passaggio 1 sopra.


PRAGMA integral_check non rileva alcun errore con lo schema.
Graymatter,

e qual è il problema con quello?
Mohammad Yahia,

1

Un'opzione, se ne hai bisogno in un pizzico e se la tua colonna iniziale è stata creata con un valore predefinito, è quella di creare la nuova colonna desiderata, copiarne il contenuto e fondamentalmente "abbandonare" la vecchia colonna (rimane presente, ma non lo usi / non aggiorni, ecc.)

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

Questo lascia dietro una colonna (e se è stato creato con NOT NULL ma senza un valore predefinito, gli inserimenti futuri che lo ignorano potrebbero non riuscire), ma se è solo una tabella usa e getta, i compromessi potrebbero essere accettabili. In caso contrario, utilizzare una delle altre risposte menzionate qui o un database diverso che consente di rinominare le colonne.



-3

sqlite3 yourdb .dump> /tmp/db.txt
modifica /tmp/db.txt cambia il nome della colonna in Crea riga
sqlite2 yourdb2 </tmp/db.txt
mv / sposta yourdb2 yourdb


3
la tua risposta non fornisce alcuna informazione, un mucchio di codice / istruzioni sputa senza ulteriori informazioni sul motivo per cui pensi che funzionerà o cosa supponiamo che accada se lo esegui
RGLSV
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.