Como renomear uma coluna em uma tabela de banco de dados SQLite?

296

Eu precisaria renomear algumas colunas em algumas tabelas em um banco de dados SQLite. Eu sei que uma pergunta semelhante foi feita anteriormente no stackoverflow, mas era para o SQL em geral, e o caso do SQLite não foi mencionado.

A partir da documentação do SQLite para ALTER TABLE , entendo que não é possível fazer isso "facilmente" (isto é, uma única instrução ALTER TABLE).

Eu queria saber se alguém sabia de uma maneira SQL genérica de fazer uma coisa dessas com o SQLite.

joce
fonte
Você pode fazer isso usando o navegador db para sqlite muito facilmente
Matt G
1
Por favor, considere marcar esta resposta como aceita stackoverflow.com/a/52346199/124486
Evan Carroll

Respostas:

66

Isso foi corrigido apenas com 15/09/2018 (3.25.0)

Aprimora o ALTER TABLEcomando:

  • Adicione suporte para renomear colunas em uma tabela usando ALTER TABLEtable RENAME COLUMN oldname TO newname.
  • Corrija o recurso de renomeação de tabela para que ele também atualize as referências à tabela renomeada em acionadores e visualizações.

Você pode encontrar a nova sintaxe documentada em ALTER TABLE

A RENAME COLUMN TOsintaxe altera o nome da coluna da tabela nome da tabela em novo nome da coluna. O nome da coluna é alterado na própria definição da tabela e também em todos os índices, gatilhos e visualizações que fazem referência à coluna. Se a alteração do nome da coluna resultar em ambiguidade semântica em um gatilho ou visualização, a RENAME COLUMNfalha ocorrerá com um erro e nenhuma alteração será aplicada.

insira a descrição da imagem aqui Fonte da imagem: https://www.sqlite.org/images/syntax/alter-table-stmt.gif

Exemplo:

CREATE TABLE tab AS SELECT 1 AS c;

SELECT * FROM tab;

ALTER TABLE tab RENAME COLUMN c to c_new;

SELECT * FROM tab;

demonstração do db-fiddle.com


Suporte Android

Até o momento, a API 27 do Android está usando o pacote SQLite versão 3.19 .

Com base na versão atual que o Android está usando e que esta atualização está chegando na versão 3.25.0 do SQLite, eu diria que você tem um pouco de espera (aproximadamente API 33) antes que o suporte para isso seja adicionado ao Android.

E, mesmo assim, se você precisar oferecer suporte a versões anteriores à API 33, não poderá usá-lo.

Lukasz Szozda
fonte
8
Estou implementando uma migração para Android e, infelizmente, o IntelliJ está mostrando um aviso de que não é um comando SQL válido. database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount"). COLUM está destacado em vermelho e diz TO esperado, obteve 'COLUMN' . Infelizmente, o Android ainda está na versão 3.19 do SQLite, e é por isso que isso não funciona para mim.
Adam Hurwitz
1
editado: Eu encontrei no system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1 , que o 1.0.109.x) está realmente usando o SQLite 3.24 e o System.Data.SQLite O uso do SQLite 3.25 está programado para ser lançado este mês.
rychlmoj
1
Para sua informação, infelizmente, isso ainda não foi implementado pela biblioteca SQLite do Android . Espero que eles sejam atualizados em breve.
Adam Hurwitz
3
Eu adicionei uma seção do Suporte do Android para impedir que outras pessoas tenham esperanças. Com base no uso atual do SQLite 3.19 do Android 27, teremos que esperar até aproximadamente a API 33 para que esse recurso seja adicionado ao Android, e mesmo assim ele será suportado apenas nas versões mais recentes. Suspiro.
Joshua Pinter
1
@ JoshuaPinter Obrigado por estender minha resposta.
Lukasz Szozda
448

Digamos que você tenha uma tabela e precise renomear "colb" para "col_b":

Primeiro você renomeia a tabela antiga:

ALTER TABLE orig_table_name RENAME TO tmp_table_name;

Em seguida, crie a nova tabela, com base na tabela antiga, mas com o nome da coluna atualizada:

CREATE TABLE orig_table_name (
  col_a INT
, col_b INT
);

Em seguida, copie o conteúdo da tabela original.

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

Por fim, largue a mesa antiga.

DROP TABLE tmp_table_name;

Envolvendo tudo isso em um BEGIN TRANSACTION;e COMMIT;também é provavelmente uma boa idéia.

Evan
fonte
51
E não esqueça seus índices.
21415 Tom Mayfield
11
Muito importante, o código de exemplo acima está sem uma transação. Você deve agrupar a coisa toda em um BEGIN / END (ou ROLLBACK) para garantir que a renomeação seja concluída com êxito ou não seja.
Roger Binns
4
Qualquer pessoa que pretenda fazer isso em android pode implementar transações usando SQLiteDatabase.beginTransaction ()
bmaupin
7
Não há nada no código na resposta que copia índices. Criar uma tabela vazia e colocar dados nela apenas copia a estrutura e os dados. Se você deseja metadados (índices, chaves estrangeiras, restrições etc.), também é necessário emitir instruções para criá-las na tabela substituída.
Tom Mayfield
17
O .schemacomando do SQLite é útil para mostrar a CREATE TABLEinstrução que compõe a tabela existente. Você pode obter sua saída, modificar conforme necessário e executá-la para criar a nova tabela. Este comando também mostra os CREATE INDEXcomandos necessários para criar os índices, que devem cobrir as preocupações de Thomas. Obviamente, certifique-se de executar este comando antes de alterar qualquer coisa.
Mike DeSimone
56

Pesquisando, encontrei essa ferramenta gráfica multiplataforma (Linux | Mac | Windows) chamada DB Browser for SQLite, que na verdade permite renomear colunas de uma maneira muito amigável!

Editar | Tabela de modificação | Selecionar tabela | Editar campo. Clique clique! Voila!

No entanto, se alguém quiser compartilhar uma maneira programática de fazer isso, ficarei feliz em saber!

joce
fonte
1
Há também um complemento do Firefox que faz a mesma coisa . Clique com o botão direito do mouse na coluna que deseja renomear e selecione "Editar coluna".
Jacob Hacker
1
Mesmo no openSUSE, ele está disponível como um pacote: software.opensuse.org/package/sqlitebrowser
É estranho que tenha tantos votos. Estamos falando de programação aqui (código). Por que você postou essa resposta aqui?
USER25
2
Não há menção de como fazer isso com o código na minha pergunta. Eu só queria saber como renomear uma coluna em um banco de dados SQLite.
joce
@joce eu te amo !!! (como um irmão) me fez mudar de campo, voila. Eu havia exportado uma tabela do MS Access para SQLite e um dos campos tinha um dígito na frente: 3YearLetterSent. O Visual Studio criou a classe da tabela, mas engasgou com o dígito "3" na frente do nome do campo. Eu sei disso, simplesmente não estava assistindo.
JustJohn
53

Embora seja verdade que não haja ALTER COLUMN, se você deseja renomear a coluna, solte a restrição NOT NULL ou altere o tipo de dados, use o seguinte conjunto de comandos:

Nota: Esses comandos podem corromper seu banco de dados, portanto, verifique se você possui um 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;

Você precisará fechar e reabrir sua conexão ou aspirar o banco de dados para recarregar as alterações no esquema.

Por exemplo:

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  

AS REFERÊNCIAS SEGUEM:


pragma writable_schema
Quando esse pragma está ativado, as tabelas SQLITE_MASTER no qual o banco de dados pode ser alterado usando as instruções UPDATE, INSERT e DELETE comuns. Aviso: o uso incorreto deste pragma pode resultar facilmente em um arquivo de banco de dados corrompido.

alterar tabela O
SQLite suporta um subconjunto limitado de ALTER TABLE. O comando ALTER TABLE no SQLite permite que o usuário renomeie uma tabela ou adicione uma nova coluna a uma tabela existente. Não é possível renomear uma coluna, remover uma coluna ou adicionar ou remover restrições de uma tabela.

ALTER TABLE SYNTAX

Noé
fonte
3
Perigoso, mas ainda provavelmente a resposta mais direta.
Tek
2
Sim extremamente rápido - Dangerous único meio "Certifique-se de que você tem uma cópia de segurança em primeiro lugar"
Noah
6
O formato do arquivo sqlite é muito simples e é por isso que esta operação é válida. O formato do arquivo possui apenas dois conjuntos de informações sobre uma tabela: o comando CREATE TABLE real como texto sem formatação e as linhas cujos valores estão aparecendo na ordem dos campos do comando CREATE. O que significa que o código sqlite abre o banco de dados, analisa cada comando CREATE e cria dinamicamente suas informações de coluna na memória. Portanto, qualquer comando que altere o comando CREATE de uma maneira que termine com o mesmo número de colunas funcionará, mesmo se você alterar o tipo ou as restrições.
Thomas Tempelmann
3
@ThomasTempelmann No entanto, adicionar restrições que não sejam atendidas pelo conjunto de dados resultará em problemas porque o planejador de consultas assume que essas restrições são válidas.
fuz 26/04/16
2
@ThomasTempelmann Remover restrições sempre é bom. Adicionar restrições é bom se a restrição for atendida por todas as linhas, mas você certamente precisará verificar.
fuz
18

Recentemente, tive que fazer isso no SQLite3 com uma tabela chamada points com as colunas id, lon, lat . Erradamente, quando a tabela foi importada, os valores de latitude foram armazenados na coluna lon e vice-versa; portanto, uma correção óbvia seria renomear essas colunas. Então o truque foi:

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;

Espero que isso seja útil para você!

aizquier
fonte
Este método não copia o valor PK adequadamente e cria automaticamente a coluna oculta do rowid. Não necessariamente um problema, mas queria salientar isso porque se tornou um problema para mim.
TPoschel 2/12/12
4
Não seria mais fácil fazer "UPDATE points SET lon = lat, lat = lon;"?
KPasso
1
Esta resposta faz o processo na ORDEM correta. Primeiro crie a tabela temporária e preencha-a e destrua o original .
Xeoncross
14

Citando a documentação do sqlite :

O SQLite suporta um subconjunto limitado de ALTER TABLE. O comando ALTER TABLE no SQLite permite que o usuário renomeie uma tabela ou adicione uma nova coluna a uma tabela existente. Não é possível renomear uma coluna, remover uma coluna ou adicionar ou remover restrições de uma tabela.

Obviamente, o que você pode fazer é criar uma nova tabela com o novo layout SELECT * FROM old_tablee preencher a nova tabela com os valores que você receberá.

Elazar Leibovich
fonte
7

Primeiro, é uma daquelas coisas que me surpreendem: renomear uma coluna requer a criação de uma tabela totalmente nova e a cópia dos dados da tabela antiga para a nova tabela ...

A GUI em que aterrei para executar operações SQLite é Base . Tem uma janela de log bacana que mostra todos os comandos que foram executados. A renomeação de uma coluna via Base preenche a janela de log com os comandos necessários:

Janela de log base

Estes podem ser facilmente copiados e colados onde você precisar. Para mim, isso está em um arquivo de migração do ActiveAndroid . Um toque interessante também é que os dados copiados incluem apenas os comandos SQLite, não os registros de data e hora, etc.

Felizmente, isso economiza tempo para algumas pessoas.

Joshua Pinter
fonte
Para sua informação, se você estiver usando o ActiveAndroid , poderá omitir as linhas BEGIN TRANSACTION;e COMMIT;, pois o ActiveAndroid lida com isso sozinho.
Joshua Pinter
6

CASO 1: SQLite 3.25.0+

Somente a versão 3.25.0 do SQLite suporta renomear colunas. Se o seu dispositivo está atendendo a esse requisito, as coisas são bem simples. A consulta abaixo resolveria seu problema:

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

CASO 2: versões anteriores do SQLite

Você precisa seguir uma abordagem diferente para obter o resultado que pode ser um pouco complicado

Por exemplo, se você tiver uma tabela como esta:

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

E se você deseja alterar o nome da coluna Location

Etapa 1: renomeie a tabela original:

ALTER TABLE student RENAME TO student_temp;

Etapa 2: agora crie uma nova tabela studentcom o nome correto da coluna:

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

Etapa 3: Copie os dados da tabela original para a nova tabela:

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

Nota: O comando acima deve ser todo uma linha.

Etapa 4: Solte a tabela original:

DROP TABLE student_temp;

Com essas quatro etapas, você pode alterar manualmente qualquer tabela SQLite. Lembre-se de que você também precisará recriar quaisquer índices, visualizadores ou gatilhos na nova tabela.

Febin Mathew
fonte
1
Como atualizar a versão do banco de dados SqlLite a 3.29.0 no estúdio android eu estou usando nível api 28.
Nathani Software
A versão SQLite é definida pelo dispositivo no qual o aplicativo funciona. Depende do dispositivo.
Febin Mathew 21/10/19
1
Para pessoas que usam o sqlite antigo, as quatro etapas acima são desencorajadas. Veja a seção "Cuidado" em sqlite.org/lang_altertable.html .
Jeff
3

alterar coluna da tabela <id> para <_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
fonte
3

Crie uma nova coluna com o nome da coluna desejada: COLNew.

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

Copie o conteúdo da coluna antiga COLOld para a nova coluna COLNew.

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

Nota: colchetes são necessários na linha acima.

Anthony Ebert
fonte
2

Como mencionado anteriormente, existe uma ferramenta SQLite Database Browser, que faz isso. Lentamente, essa ferramenta mantém um registro de todas as operações executadas pelo usuário ou pelo aplicativo. Fazendo isso uma vez e olhando para o log do aplicativo, você verá o código envolvido. Copie a consulta e cole conforme necessário. Trabalhou para mim. Espero que isto ajude

Chris Lytridis
fonte
2

A partir da documentação oficial

Opcionalmente, um procedimento mais simples e rápido pode ser usado para algumas alterações que não afetam o conteúdo do disco de forma alguma. O procedimento mais simples a seguir é apropriado para remover as restrições CHECK ou FOREIGN KEY ou NOT NULL, renomear colunas ou adicionar ou remover ou alterar valores padrão em uma coluna.

  1. Inicie uma transação.

  2. Execute PRAGMA schema_version para determinar o número da versão atual do esquema. Esse número será necessário para a etapa 6 abaixo.

  3. Ative a edição do esquema usando PRAGMA writable_schema = ON.

  4. Execute uma instrução UPDATE para alterar a definição da tabela X na tabela sqlite_master: UPDATE sqlite_master SET sql = ... WHERE type = 'table' AND name = 'X';

    Cuidado: Fazer uma alteração na tabela sqlite_master como esta tornará o banco de dados corrompido e ilegível se a alteração contiver um erro de sintaxe. Sugere-se que um teste cuidadoso da instrução UPDATE seja feito em um banco de dados em branco separado antes de usá-lo em um banco de dados contendo dados importantes.

  5. Se a alteração na tabela X também afetar outras tabelas ou índices ou gatilhos são visualizações no esquema, execute as instruções UPDATE para modificar também esses outros índices e tabelas de tabelas. Por exemplo, se o nome de uma coluna mudar, todas as restrições, gatilhos, índices e visualizações FOREIGN KEY que se referem a essa coluna deverão ser modificados.

    Cuidado: Mais uma vez, fazer alterações na tabela sqlite_master como esta tornará o banco de dados corrompido e ilegível se a alteração contiver um erro. Teste com cuidado todo esse procedimento em um banco de dados de teste separado antes de usá-lo em um banco de dados contendo dados importantes e / ou faça cópias de backup de bancos de dados importantes antes de executar este procedimento.

  6. Incremente o número da versão do esquema usando PRAGMA schema_version = X em que X é um a mais que o número da versão do esquema antigo encontrado na etapa 2 acima.

  7. Desative a edição de esquema usando PRAGMA writable_schema = OFF.

  8. (Opcional) Execute PRAGMA truth_check para verificar se as alterações no esquema não danificaram o banco de dados.

  9. Confirme a transação iniciada na etapa 1 acima.

Mohammad Yahia
fonte
O PRAGMA integridade_check não identifica nenhum erro no esquema.
Graymatter
e qual é o problema com isso?
Mohammad Yahia
1

Uma opção, se você precisar fazer isso rapidamente e se sua coluna inicial foi criada com o padrão, é criar a nova coluna desejada, copiar o conteúdo para ela e basicamente "abandonar" a coluna antiga (ela permanece presente, mas você simplesmente não o usa / atualiza, 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

Isso deixa para trás uma coluna (e se ela foi criada com NOT NULL, mas sem um padrão, as inserções futuras que a ignoram podem falhar), mas se for apenas uma tabela descartável, as compensações podem ser aceitáveis. Caso contrário, use uma das outras respostas mencionadas aqui ou um banco de dados diferente que permita que as colunas sejam renomeadas.

rogerdpack
fonte
-3

sqlite3 yourdb .dump> /tmp/db.txt
edite /tmp/db.txt altere o nome da coluna na linha Criar
sqlite2 yourdb2 </tmp/db.txt
mv / mova yourdb2 yourdb

H Bosch
fonte
3
você está resposta não fornece qualquer informação, um monte de código / instruções cuspir sem qualquer informação extra sobre por que você acha que vai funcionar ou o que é suposto acontecer se você executá-lo
RGLSV