¿Cómo cambio el nombre de una columna en una tabla de base de datos SQLite?

296

Necesitaría cambiar el nombre de algunas columnas en algunas tablas en una base de datos SQLite. Sé que se ha hecho una pregunta similar en stackoverflow anteriormente, pero fue para SQL en general, y el caso de SQLite no se mencionó.

De la documentación de SQLite para ALTER TABLE , deduzco que no es posible hacer tal cosa "fácilmente" (es decir, una sola declaración ALTER TABLE).

Me preguntaba si alguien sabía de una forma genérica de SQL de hacer tal cosa con SQLite.

joce
fuente
Puede hacerlo usando db browser para sqlite con bastante facilidad
Matt G
1
Considere marcar esta respuesta como aceptada stackoverflow.com/a/52346199/124486
Evan Carroll

Respuestas:

66

Esto solo se solucionó con 2018-09-15 (3.25.0)

Mejoras en el ALTER TABLEcomando:

  • Añadir soporte para cambiar el nombre de las columnas dentro de una tabla utilizando ALTER TABLEla tabla RENAME COLUMN oldname TO newname.
  • Se corrigió la función de cambio de nombre de la tabla para que también actualice las referencias a la tabla renombrada en disparadores y vistas.

Puede encontrar la nueva sintaxis documentada en ALTER TABLE

La RENAME COLUMN TOsintaxis cambia el nombre de columna de la tabla nombre-tabla en nombre-nueva-columna. El nombre de la columna se cambia tanto en la definición de la tabla como en todos los índices, desencadenantes y vistas que hacen referencia a la columna. Si el cambio de nombre de columna daría lugar a una ambigüedad semántica en un disparador o vista, entonces RENAME COLUMNfalla con un error y no se aplican cambios.

ingrese la descripción de la imagen aquí Fuente de la imagen: https://www.sqlite.org/images/syntax/alter-table-stmt.gif

Ejemplo:

CREATE TABLE tab AS SELECT 1 AS c;

SELECT * FROM tab;

ALTER TABLE tab RENAME COLUMN c to c_new;

SELECT * FROM tab;

demo db-fiddle.com


Soporte de Android

Al momento de escribir, la API 27 de Android está utilizando el paquete SQLite versión 3.19 .

Basado en la versión actual que está usando Android y que esta actualización viene en la versión 3.25.0 de SQLite, diría que tiene que esperar un poco (aproximadamente API 33) antes de que se agregue soporte para Android.

Y, aun así, si necesita admitir versiones anteriores a la API 33, no podrá usar esto.

Lukasz Szozda
fuente
8
Estoy implementando una migración de Android y desafortunadamente IntelliJ muestra una advertencia de que no es un comando SQL válido. database.execSQL("ALTER TABLE content RENAME COLUMN archiveCount TO dismissCount"). COLUM está resaltado en rojo y dice TO esperado, obtuvo 'COLUMNA' . Desafortunadamente, Android todavía está en SQLite versión 3.19, por lo que esto no funciona para mí.
Adam Hurwitz
1
editado: He encontrado en system.data.sqlite.org/index.html/doc/trunk/www/faq.wiki#q1 , que el 1.0.109.x) está usando SQLite 3.24 y System.Data.SQLite El uso de SQLite 3.25 está programado para ser relanzado este mes.
rychlmoj
1
Para su información, lamentablemente esto aún no se ha implementado por la biblioteca SQLite de Android . Esperemos que se actualicen pronto.
Adam Hurwitz
3
Agregué una sección para el Soporte de Android para evitar que otros se ilusionen. Basado en el uso actual de Android 27 de SQLite 3.19, tendremos que esperar hasta aproximadamente API 33 antes de que esta característica se agregue a Android, e incluso entonces solo será compatible con las últimas versiones. Suspiro.
Joshua Pinter
1
@ JoshuaPinter Gracias por extender mi respuesta.
Lukasz Szozda
448

Digamos que tiene una tabla y necesita cambiar el nombre de "colb" a "col_b":

Primero cambia el nombre de la tabla anterior:

ALTER TABLE orig_table_name RENAME TO tmp_table_name;

Luego cree la nueva tabla, basada en la tabla anterior pero con el nombre de la columna actualizada:

CREATE TABLE orig_table_name (
  col_a INT
, col_b INT
);

Luego copie el contenido de la tabla original.

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

Por último, deja caer la vieja mesa.

DROP TABLE tmp_table_name;

Envolver todo esto en un BEGIN TRANSACTION;y COMMIT;también es probablemente una buena idea.

Evan
fuente
51
Y no olvides tus índices.
Tom Mayfield
11
Muy importante, al código de ejemplo anterior le falta una transacción. Debe envolver todo en un COMIENZO / FIN (o ROLLBACK) para asegurarse de que el cambio de nombre se complete con éxito o no se complete.
Roger Binns
44
Cualquiera que desee hacer esto en Android puede implementar transacciones usando SQLiteDatabase.beginTransaction ()
bmaupin
77
No hay nada en el código en la respuesta que copie índices. Crear una tabla vacía y poner datos en ella solo copia la estructura y los datos. Si desea metadatos (índices, claves foráneas, restricciones, etc.), también debe emitir sentencias para crearlas en la tabla reemplazada.
Tom Mayfield
17
El .schemacomando de SQLite es útil para mostrar la CREATE TABLEdeclaración que hace la tabla existente. Puede tomar su salida, modificarla según sea necesario y ejecutarla para crear la nueva tabla. Este comando también muestra los CREATE INDEXcomandos necesarios para crear los índices, que deben cubrir las preocupaciones de Thomas. Por supuesto, asegúrese de ejecutar este comando antes de modificar cualquier cosa.
Mike DeSimone
56

Al buscar, encontré esta herramienta gráfica multiplataforma (Linux | Mac | Windows) llamada DB Browser para SQLite que en realidad permite cambiar el nombre de las columnas de una manera muy fácil de usar.

Editar | Modificar tabla | Seleccionar tabla | Editar campo. ¡Clic clic! Voila!

Sin embargo, si alguien quiere compartir una forma programática de hacer esto, ¡me encantaría saberlo!

joce
fuente
1
También hay un complemento de Firefox que hace lo mismo , haga clic derecho en la columna que desea cambiar de nombre y seleccione "Editar columna".
Jacob Hacker
1
Incluso en openSUSE, está disponible como un paquete: software.opensuse.org/package/sqlitebrowser
Es extraño que tenga tantos votos. Estamos hablando de programación aquí (código). ¿Por qué publicaste esta respuesta aquí?
usuario25
2
No se menciona cómo hacer esto con el código en mi pregunta. Solo quería saber cómo cambiar el nombre de una columna en un SQLite DB.
Joce
@joce te amo !!! (como un hermano) me metió en el campo cambiado, voila. Había exportado una tabla de MS Access a SQLite y uno de los campos tenía un dígito al frente: 3YearLetterSent. Visual Studio hizo la clase de la tabla pero se atragantó con el dígito "3" en la parte delantera del nombre del campo. Lo sé, simplemente no estaba mirando.
JustJohn
53

Si bien es cierto que no hay ALTER COLUMN, si solo desea cambiar el nombre de la columna, descartar la restricción NOT NULL o cambiar el tipo de datos, puede usar el siguiente conjunto de comandos:

Nota: estos comandos tienen el potencial de dañar su base de datos, así que asegúrese de tener una copia de seguridad

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;

Deberá cerrar y volver a abrir su conexión o aspirar la base de datos para volver a cargar los cambios en el esquema.

Por ejemplo:

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  

REFERENCIAS SIGUEN:


pragma writable_schema
Cuando este pragma está activado, las tablas SQLITE_MASTER en las que la base de datos se puede cambiar utilizando las instrucciones ordinarias UPDATE, INSERT y DELETE. Advertencia: el mal uso de este pragma puede resultar fácilmente en un archivo de base de datos corrupto.

alter table
SQLite admite un subconjunto limitado de ALTER TABLE. El comando ALTER TABLE en SQLite permite al usuario cambiar el nombre de una tabla o agregar una nueva columna a una tabla existente. No es posible cambiar el nombre de una columna, eliminar una columna o agregar o eliminar restricciones de una tabla.

ALTERAR SINTAXIS DE TABLA

Noé
fuente
3
Peligroso, pero sigue siendo probablemente la respuesta más directa de la OMI.
Tek
2
Sí, extremadamente rápido - Peligroso solo significa "Asegúrese de tener una copia de seguridad primero"
Noah
66
El formato de archivo sqlite es muy simple y es por eso que esta operación es válida. El formato de archivo tiene solo dos conjuntos de información sobre una tabla: el comando CREATE TABLE real como texto sin formato y las filas, cuyos valores aparecen en el orden de los campos del comando CREATE. Lo que significa que el código sqlite abre la base de datos, analiza cada comando CREATE y construye dinámicamente la información de su columna en la memoria. Por lo tanto, cualquier comando que altere el comando CREATE de una manera que termine con el mismo número de columnas funcionará, incluso si cambia su tipo o restricciones.
Thomas Tempelmann
3
@ThomasTempelmann Sin embargo, agregar restricciones que el conjunto de datos no cumple generará problemas porque el planificador de consultas asume que las restricciones se mantienen.
fuz
2
@ThomasTempelmann Eliminar restricciones siempre está bien. Agregar restricciones está bien si todas las filas satisfacen la restricción, pero ciertamente debe verificarla.
fuz
18

Recientemente tuve que hacer eso en SQLite3 con una tabla llamada puntos con los colunms id, lon, lat . Por error, cuando se importó la tabla, los valores de latitud se almacenaron en la columna lon y viceversa, por lo que una solución obvia sería cambiar el nombre de esas columnas. Entonces el truco fue:

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 esto te sea útil!

aizquier
fuente
Este método no copia el valor PK de forma adecuada y crea automáticamente la columna oculta rowid. No necesariamente es un problema, pero quería señalarlo porque se convirtió en un problema para mí.
TPoschel
44
¿No sería más fácil hacer "ACTUALIZAR puntos SET lon = lat, lat = lon;"?
kstep
1
Esta respuesta hace el proceso en el PEDIDO correcto. Primero cree la tabla temporal y llénela, luego destruya el original .
Xeoncross
14

Citando la documentación de sqlite :

SQLite admite un subconjunto limitado de ALTER TABLE. El comando ALTER TABLE en SQLite permite al usuario cambiar el nombre de una tabla o agregar una nueva columna a una tabla existente. No es posible cambiar el nombre de una columna, eliminar una columna o agregar o eliminar restricciones de una tabla.

Lo que puede hacer, por supuesto, es crear una nueva tabla con el nuevo diseño SELECT * FROM old_tabley llenar la nueva tabla con los valores que recibirá.

Elazar Leibovich
fuente
7

En primer lugar, esta es una de esas cosas que me golpea en la cara con sorpresa: cambiar el nombre de una columna requiere crear una tabla completamente nueva y copiar los datos de la tabla anterior a la nueva tabla ...

La GUI en la que he aterrizado para hacer operaciones SQLite es Base . Tiene una ingeniosa ventana de registro que muestra todos los comandos que se han ejecutado. Hacer un cambio de nombre de una columna a través de Base llena la ventana de registro con los comandos necesarios:

Ventana de registro base

Estos se pueden copiar y pegar fácilmente donde los necesite. Para mí, eso está en un archivo de migración ActiveAndroid . Un buen detalle también es que los datos copiados solo incluyen los comandos SQLite, no las marcas de tiempo, etc.

Con suerte, eso ahorra tiempo a algunas personas.

Joshua Pinter
fuente
Para su información, si está utilizando ActiveAndroid , puede omitir las líneas BEGIN TRANSACTION;y COMMIT;, ya que ActiveAndroid lo maneja por sí mismo.
Joshua Pinter
6

CASO 1: SQLite 3.25.0+

Solo la versión 3.25.0 de SQLite admite cambiar el nombre de las columnas. Si su dispositivo cumple con este requisito, las cosas son bastante simples. La siguiente consulta resolvería su problema:

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

CASO 2: SQLite Versiones anteriores

Tienes que seguir un enfoque diferente para obtener el resultado, que puede ser un poco complicado

Por ejemplo, si tiene una tabla como esta:

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

Y si deseas cambiar el nombre de la columna Location

Paso 1: cambie el nombre de la tabla original:

ALTER TABLE student RENAME TO student_temp;

Paso 2: ahora cree una nueva tabla studentcon el nombre de columna correcto:

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

Paso 3: copie los datos de la tabla original a la nueva tabla:

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

Nota: El comando anterior debe ser una sola línea.

Paso 4: suelte la tabla original:

DROP TABLE student_temp;

Con estos cuatro pasos puede cambiar manualmente cualquier tabla SQLite. Tenga en cuenta que también necesitará recrear cualquier índice, visor o activador en la nueva tabla.

Febin Mathew
fuente
1
Cómo actualizar la versión de base de datos SQLLite a 3.29.0 en el estudio androide que estoy usando API de nivel 28.
Nathani Software
La versión de SQLite está definida por el dispositivo en el que funciona la aplicación. Depende del dispositivo.
Febin Mathew
1
Para las personas que usan sqlite antiguo, se desaconsejan los cuatro pasos anteriores. Consulte la sección "Precaución" en sqlite.org/lang_altertable.html .
Jeff
3

cambiar la columna de la tabla <id> a <_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
fuente
3

Cree una nueva columna con el nombre de columna deseado: COLNew.

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

Copie el contenido de la antigua columna COLOld a la nueva columna COLNew.

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

Nota: los corchetes son necesarios en la línea anterior.

Anthony Ebert
fuente
2

Como se mencionó anteriormente, hay una herramienta SQLite Database Browser, que hace esto. Afortunadamente, esta herramienta mantiene un registro de todas las operaciones realizadas por el usuario o la aplicación. Al hacer esto una vez y mirar el registro de la aplicación, verá el código involucrado. Copie la consulta y péguela según sea necesario. Trabajó para mi. Espero que esto ayude

Chris Lytridis
fuente
2

De la documentación oficial.

Opcionalmente, se puede utilizar un procedimiento más simple y más rápido para algunos cambios que no afectan el contenido del disco de ninguna manera. El siguiente procedimiento más simple es apropiado para eliminar las restricciones CHECK o FOREIGN KEY o NOT NULL, cambiar el nombre de las columnas o agregar o eliminar o cambiar los valores predeterminados en una columna.

  1. Comience una transacción.

  2. Ejecute PRAGMA schema_version para determinar el número de versión del esquema actual. Este número será necesario para el paso 6 a continuación.

  3. Active la edición de esquemas usando PRAGMA writable_schema = ON.

  4. Ejecute una instrucción UPDATE para cambiar la definición de la tabla X en la tabla sqlite_master: UPDATE sqlite_master SET sql = ... WHERE type = 'table' AND name = 'X';

    Precaución: Realizar un cambio en la tabla sqlite_master de esta manera hará que la base de datos esté corrupta e ilegible si el cambio contiene un error de sintaxis. Se sugiere que las pruebas cuidadosas de la declaración ACTUALIZACIÓN se realicen en una base de datos en blanco separada antes de usarla en una base de datos que contenga datos importantes.

  5. Si el cambio a la tabla X también afecta a otras tablas o índices, o los desencadenantes son vistas dentro del esquema, entonces ejecute las instrucciones ACTUALIZAR para modificar esos índices y vistas de otras tablas también. Por ejemplo, si cambia el nombre de una columna, se deben modificar todas las restricciones, desencadenantes, índices y vistas de FOREIGN KEY que se refieren a esa columna.

    Precaución: una vez más, realizar cambios en la tabla sqlite_master como esta hará que la base de datos se corrompa e ilegible si el cambio contiene un error. Pruebe cuidadosamente todo este procedimiento en una base de datos de prueba separada antes de usarlo en una base de datos que contenga datos importantes y / o haga copias de seguridad de bases de datos importantes antes de ejecutar este procedimiento.

  6. Incremente el número de versión del esquema utilizando PRAGMA schema_version = X donde X es uno más que el número de versión del esquema anterior que se encuentra en el paso 2 anterior.

  7. Deshabilite la edición de esquemas usando PRAGMA writable_schema = OFF.

  8. (Opcional) Ejecute PRAGMA integridad_check para verificar que los cambios en el esquema no dañaron la base de datos.

  9. Confirme la transacción iniciada en el paso 1 anterior.

Mohammad Yahia
fuente
PRAGMA integrity_check no detecta ningún error con el esquema.
Graymatter
y cual es el problema con eso?
Mohammad Yahia
1

Una opción, si necesita hacerlo en un apuro, y si su columna inicial se creó con un valor predeterminado, es crear la nueva columna que desee, copiar el contenido y básicamente "abandonar" la columna anterior (permanece presente, pero simplemente no lo usa / actualiza, 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

Esto deja una columna (y si se creó con NOT NULL pero sin un valor predeterminado, las inserciones futuras que lo ignoren podrían fallar), pero si se trata solo de una tabla desechable, las compensaciones podrían ser aceptables. De lo contrario, use una de las otras respuestas mencionadas aquí, o una base de datos diferente que permita cambiar el nombre de las columnas.

rogerdpack
fuente
-3

sqlite3 yourdb .dump> /tmp/db.txt
editar /tmp/db.txt cambiar el nombre de la columna en Crear línea
sqlite2 yourdb2 </tmp/db.txt
mv / move yourdb2 yourdb

H Bosch
fuente
3
su respuesta no proporciona ninguna información, se escupe un montón de código / instrucciones sin ninguna información adicional sobre por qué cree que funcionará o qué se supone que sucederá si lo ejecuta
RGLSV