Gestionar una base de datos implica a menudo la necesidad de adaptar su estructura a lo largo del tiempo. En el caso particular de SQLite, un motor de base de datos ligero y embebido, esta tarea de modificación de esquema se realiza principalmente a través de la sentencia ALTER TABLE. Sin embargo, a diferencia de sistemas de bases de datos más robustos, SQLite tiene limitaciones específicas en cuanto a qué tipo de modificaciones directas permite. Comprender estas limitaciones y los métodos alternativos es fundamental para trabajar eficazmente con SQLite.

SQLite almacena la definición del esquema (la estructura de las tablas, índices, etc.) como texto plano dentro de la tabla interna sqlite_schema. Esta característica, que contribuye a su portabilidad y simplicidad, es también la razón principal de las restricciones en ALTER TABLE. Modificar la estructura implica editar y reinterpretar este texto, lo cual puede ser complejo para ciertos cambios.

Operaciones Directas con ALTER TABLE
A pesar de sus limitaciones, ALTER TABLE en SQLite soporta directamente algunas operaciones comunes. Estas son las que se realizan de forma más eficiente, ya que a menudo solo implican la modificación de la definición del esquema en sqlite_schema sin necesidad de reescribir completamente los datos de la tabla, a menos que se apliquen nuevas restricciones a datos existentes o se eliminen columnas.
Renombrar una Tabla
La operación más sencilla es cambiar el nombre de una tabla existente. Esto se logra con la sintaxis ALTER TABLE table_name RENAME TO new_table_name.
ALTER TABLE clientes RENAME TO usuarios;Esta operación es rápida y eficiente. Desde versiones recientes (a partir de la 3.25.0), SQLite es capaz de actualizar automáticamente las referencias a la tabla renombrada en triggers, vistas y (desde la 3.26.0) restricciones de clave foránea, siempre y cuando no se use la opción de compatibilidad PRAGMA legacy_alter_table=ON.
Añadir una Columna
Puedes añadir una nueva columna al final de una tabla existente utilizando ALTER TABLE table_name ADD COLUMN column_def.
ALTER TABLE usuarios ADD COLUMN email VARCHAR(100);La definición de la columna (column_def) sigue las mismas reglas que en CREATE TABLE, pero con algunas restricciones importantes:
- La nueva columna no puede tener una restricción
PRIMARY KEYoUNIQUE. - No puede tener un valor por defecto que sea
CURRENT_TIME,CURRENT_DATE,CURRENT_TIMESTAMP, o una expresión entre paréntesis. - Si tiene una restricción
NOT NULL, debe especificar un valor por defecto distinto deNULL. - Si las claves foráneas están activas y la columna tiene una cláusula
REFERENCES, debe tener un valor por defectoNULL. - Las columnas generadas (
GENERATED ALWAYS) solo pueden serVIRTUAL, noSTORED.
Es importante notar que si añades una columna con una restricción CHECK o una columna generada con NOT NULL (desde la versión 3.37.0), SQLite verificará esta nueva restricción contra todas las filas existentes. Si alguna fila no cumple la restricción, la operación ADD COLUMN fallará.
Renombrar una Columna
Desde versiones más recientes de SQLite, es posible renombrar directamente una columna utilizando ALTER TABLE table_name RENAME COLUMN column_name TO new_column_name.
ALTER TABLE usuarios RENAME COLUMN email TO correo;Esta operación es bastante conveniente, ya que SQLite intentará actualizar las referencias a esta columna en índices, triggers y vistas. Sin embargo, si el cambio de nombre crea una ambigüedad semántica en alguna parte del esquema (como en una vista), la operación fallará.
Eliminar una Columna
De manera similar a renombrar, la eliminación directa de columnas es una característica más reciente (desde la versión 3.35.0). Se utiliza ALTER TABLE table_name DROP COLUMN column_name.
ALTER TABLE usuarios DROP COLUMN correo;Esta operación es más compleja internamente, ya que SQLite debe reescribir los datos de la tabla para eliminar la información asociada a la columna. Además, tiene varias restricciones que a menudo impiden su uso directo:
- La columna no puede ser parte de la clave primaria.
- No puede tener una restricción
UNIQUE. - No puede estar indexada.
- No puede ser referenciada en la cláusula
WHEREde un índice parcial. - No puede ser referenciada en restricciones
CHECKoFOREIGN KEYde otras columnas o de la propia tabla. - No puede ser utilizada en la expresión de una columna generada.
- No puede aparecer en triggers o vistas.
Debido a estas numerosas restricciones, la eliminación directa de columnas a menudo no es posible, y se debe recurrir al método alternativo que explicaremos a continuación.
Realizando Cambios Más Complejos: La Técnica del "Nuevo Tabla"
Dado que las operaciones directas de ALTER TABLE en SQLite son limitadas (especialmente para modificar el tipo de dato de una columna, cambiar restricciones existentes, reordenar columnas, o eliminar columnas con dependencias), la forma estándar de realizar modificaciones de esquema más complejas es utilizar una secuencia de pasos que implica crear una nueva tabla con la estructura deseada, copiar los datos, eliminar la tabla antigua y renombrar la nueva.

Este procedimiento, aunque más laborioso, es muy versátil y permite realizar prácticamente cualquier cambio de esquema. Aquí se presenta una versión simplificada de los pasos:
- Desactivar Claves Foráneas: Si están activas, es recomendable desactivarlas temporalmente para evitar problemas durante la copia de datos:
PRAGMA foreign_keys=OFF; - Iniciar una Transacción: Agrupa todas las operaciones en una sola transacción para asegurar que, si algo falla, la base de datos permanezca en un estado coherente:
BEGIN TRANSACTION; - Guardar Definiciones de Objetos Relacionados: Consulta
sqlite_schemapara obtener las definiciones de índices, triggers y vistas asociados a la tabla que vas a modificar. Necesitarás recrearlos más tarde. Por ejemplo:SELECT type, sql FROM sqlite_schema WHERE tbl_name='nombre_tabla'; - Renombrar la Tabla Original: Cambia el nombre de la tabla existente a un nombre temporal:
ALTER TABLE nombre_tabla RENAME TO nombre_tabla_old; - Crear la Nueva Tabla: Define la nueva tabla con la estructura deseada (nuevos tipos de datos, columnas, restricciones, orden de columnas, etc.) utilizando el nombre original:
CREATE TABLE nombre_tabla (...); - Copiar los Datos: Inserta los datos de la tabla antigua en la nueva. Selecciona solo las columnas relevantes y asegúrate de que el orden y los tipos de datos sean compatibles:
INSERT INTO nombre_tabla (col1, col2, ...) SELECT col1, col2, ... FROM nombre_tabla_old; - Eliminar la Tabla Antigua: Una vez que los datos estén seguros en la nueva tabla, elimina la tabla temporal:
DROP TABLE nombre_tabla_old; - Recrear Índices, Triggers y Vistas: Utiliza las definiciones guardadas en el paso 3 (ajustadas si es necesario debido a los cambios en el esquema) para recrear estos objetos.
- Verificar Claves Foráneas: Si desactivaste las claves foráneas, puedes verificar su integridad antes de reactivarlas:
PRAGMA foreign_key_check; - Confirmar la Transacción: Finaliza la transacción para aplicar todos los cambios:
COMMIT; - Reactivar Claves Foráneas: Si las desactivaste, vuelve a activarlas:
PRAGMA foreign_keys=ON;
Ejemplo de Modificación de Tipo de Dato
Supongamos que tienes una tabla productos con una columna precio definida como INTEGER y quieres cambiarla a REAL:
-- Tabla original CREATE TABLE productos (id INTEGER PRIMARY KEY, nombre TEXT, precio INTEGER); -- Pasos para modificar la columna precio a REAL PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; ALTER TABLE productos RENAME TO productos_old; CREATE TABLE productos (id INTEGER PRIMARY KEY, nombre TEXT, precio REAL); INSERT INTO productos (id, nombre, precio) SELECT id, nombre, precio FROM productos_old; DROP TABLE productos_old; -- Aquí recrearías índices/triggers si existieran COMMIT; PRAGMA foreign_keys=ON;Este procedimiento es seguro y es el método recomendado para cambios que no son soportados directamente por ALTER TABLE.
Comparativa de Métodos
Para ayudarte a decidir qué método usar, aquí tienes una tabla comparativa:
| Operación | Método Directo ALTER TABLE | Método del "Nuevo Tabla" | Notas |
|---|---|---|---|
| Renombrar Tabla | Sí (RENAME TO) | Sí (como parte del proceso) | Método directo es más simple y eficiente. |
| Añadir Columna | Sí (ADD COLUMN) | Sí (definiendo la nueva columna) | Método directo es preferible si cumple restricciones. |
| Renombrar Columna | Sí (RENAME COLUMN, versiones recientes) | Sí (seleccionando con nuevo nombre) | Método directo es más simple si no hay conflictos. |
| Eliminar Columna | Sí (DROP COLUMN, versiones recientes) | Sí (excluyendo la columna) | DROP COLUMN tiene muchas restricciones. El método del "Nuevo Tabla" es más fiable. |
| Modificar Tipo de Dato Columna | No | Sí (definiendo nuevo tipo) | El método del "Nuevo Tabla" es necesario. |
| Cambiar Restricciones (NOT NULL, CHECK, UNIQUE, etc.) | Limitado (solo al añadir columna, o DROP/ADD si es posible) | Sí (definiendo nuevas restricciones) | El método del "Nuevo Tabla" es generalmente necesario para modificar o añadir restricciones complejas a datos existentes. |
| Reordenar Columnas | No | Sí (definiendo el nuevo orden) | El método del "Nuevo Tabla" es necesario. |
Como se observa, el método del "Nuevo Tabla" es el más flexible y te permite realizar cualquier tipo de modificación en la estructura de una tabla, aunque implique más pasos y pueda ser más lento para tablas muy grandes al requerir la copia de datos.
Consideraciones Adicionales
- Versiones de SQLite: Las capacidades directas de
RENAME COLUMNyDROP COLUMNson relativamente nuevas. Si trabajas con versiones antiguas de SQLite, el método del "Nuevo Tabla" será tu única opción para estas operaciones. - Rendimiento: Las operaciones directas de
ALTER TABLE(renombrar tabla, añadir columna sin restricciones complejas) son muy rápidas, ya que solo modifican el esquema. El método del "Nuevo Tabla" requiere copiar todos los datos, lo que puede ser lento para tablas grandes. La eliminación de columnas conDROP COLUMNtambién requiere reescribir datos, por lo que su rendimiento es comparable al método del "Nuevo Tabla" para esa operación específica. PRAGMA writable_schema=ON: Existe un PRAGMA que permite modificar directamente la tablasqlite_schema. Sin embargo, esto es extremadamente peligroso y solo debe ser usado por expertos para corregir esquemas corruptos o realizar modificaciones muy específicas y bien entendidas. Un error al usarlo puede dañar permanentemente la base de datos. Generalmente, no es el método recomendado para modificaciones de esquema rutinarias.
Preguntas Frecuentes
Aquí respondemos algunas dudas comunes sobre la modificación de tablas en SQLite:
¿Puedo cambiar el tipo de dato de una columna directamente con ALTER TABLE?
No, SQLite no soporta directamente el cambio de tipo de dato de una columna existente con ALTER TABLE. Debes usar la técnica del "Nuevo Tabla".
¿Es seguro usar el método del "Nuevo Tabla"?
Sí, si se realiza dentro de una transacción (BEGIN TRANSACTION y COMMIT) y se siguen los pasos cuidadosamente, incluyendo la verificación de claves foráneas si aplica. Una transacción asegura que o bien todos los cambios se aplican correctamente, o ninguno se aplica si hay un error.
¿Qué pasa con los datos existentes al modificar una columna?
Al usar el método del "Nuevo Tabla", los datos se copian a la nueva tabla. Si cambias el tipo de dato, SQLite intentará convertir los valores existentes al nuevo tipo. Si la conversión falla para alguna fila (por ejemplo, intentando convertir texto no numérico a número), la operación de inserción fallará. Al eliminar una columna, simplemente no se copia esa columna.
¿Por qué SQLite es diferente en su manejo de ALTER TABLE?
SQLite almacena su esquema como texto en lugar de una estructura de datos interna parseada. Esto tiene ventajas para una base de datos embebida (menor tamaño, portabilidad, compatibilidad hacia atrás), pero hace que la modificación de la estructura del esquema sea más compleja, ya que implica editar y revalidar este texto.
¿Siempre tengo que desactivar las claves foráneas para el método del "Nuevo Tabla"?
Es altamente recomendable desactivarlas (PRAGMA foreign_keys=OFF) antes de iniciar la transacción y reactivarlas al final (PRAGMA foreign_keys=ON), verificando la integridad (PRAGMA foreign_key_check). Esto simplifica el proceso de copia de datos y evita posibles errores de violación de restricciones temporales durante la manipulación de tablas.
Conclusión
Modificar la estructura de las tablas en SQLite es una tarea común que se aborda con la sentencia ALTER TABLE para operaciones directas como renombrar tablas, añadir columnas, y (en versiones recientes) renombrar o eliminar columnas. Sin embargo, debido a la forma en que SQLite gestiona su esquema, para cambios más complejos como modificar tipos de datos, cambiar restricciones o reordenar columnas, es necesario emplear un procedimiento manual de varios pasos que implica crear una nueva tabla, copiar los datos, eliminar la antigua y renombrar la nueva.
Comprender las capacidades y limitaciones de ALTER TABLE directo, así como dominar la técnica del "Nuevo Tabla", te permitirá gestionar eficientemente la evolución de tus bases de datos SQLite, adaptándolas a los requerimientos cambiantes de tus aplicaciones.
Si quieres conocer otros artículos parecidos a Modificar Esquema de Tablas en SQLite puedes visitar la categoría Bases de datos.

Aprende mas sobre MySQL