HOWTO · SQLite
Agregar una nueva columna entre dos columnas en SQLite
En este artículo, discutimos cómo insertar o agregar una nueva columna a la base de datos existente.
En esta página
SQLite no ofrece una opción de posición para ALTER TABLE ... ADD COLUMN: la columna nueva se agrega después de las columnas existentes. Para colocarla entre dos columnas, crea una tabla de reemplazo con el orden deseado, copia en ella los datos anteriores y, después, sustituye la tabla original. El ejemplo siguiente agrega phone_number entre first_name y last_name en una tabla customers.
Por qué SQLite no puede colocar una columna nueva entre columnas existentes
La documentación de ALTER TABLE de SQLite describe ADD COLUMN; esta operación agrega la columna al final de la definición de la tabla. No hay una cláusula FIRST ni AFTER para elegir su posición. Por ejemplo, ALTER TABLE customers ADD COLUMN phone_number TEXT agrega phone_number al final; no puede colocarla entre first_name y last_name.
Si solo necesitas que exista la columna nueva, agregarla al final es más sencillo y evita reconstruir la tabla. Si su posición importa para un consumidor que lee las columnas por índice ordinal, reconstruye la tabla. En las consultas de la aplicación, es preferible nombrar las columnas explícitamente para que su comportamiento no dependa del orden físico.
Reconstruir la tabla con la columna en la posición deseada
Define la tabla de reemplazo con todas las columnas necesarias en el orden previsto. Conserva los tipos originales, las claves primarias, la nulabilidad, los valores predeterminados, las reglas de unicidad y las demás restricciones. Este pequeño ejemplo usa una base de datos en memoria y una tabla independiente, por lo que permite mostrar la migración sin archivos ni servicios externos.
Ejecuta este ejemplo completo en Python:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
import sqlite3
connection = sqlite3.connect(":memory:")
connection.execute("CREATE TABLE customers (customer_id INTEGER PRIMARY KEY, first_name TEXT NOT NULL, last_name TEXT NOT NULL, email TEXT NOT NULL UNIQUE)")
connection.executemany(
"INSERT INTO customers (customer_id, first_name, last_name, email) VALUES (?, ?, ?, ?)",
[(1, "Ada", "Lovelace", "ada@example.com"), (2, "Grace", "Hopper", "grace@example.com")],
)
connection.execute("CREATE TABLE customers_new (customer_id INTEGER PRIMARY KEY, first_name TEXT NOT NULL, phone_number TEXT NOT NULL DEFAULT '', last_name TEXT NOT NULL, email TEXT NOT NULL UNIQUE)")
connection.execute("INSERT INTO customers_new (customer_id, first_name, phone_number, last_name, email) SELECT customer_id, first_name, '', last_name, email FROM customers")
connection.execute("DROP TABLE customers")
connection.execute("ALTER TABLE customers_new RENAME TO customers")
print([column[1] for column in connection.execute("PRAGMA table_info(customers)")])
print(connection.execute("SELECT customer_id, first_name, phone_number, last_name, email FROM customers ORDER BY customer_id").fetchall())
connection.close()
['customer_id', 'first_name', 'phone_number', 'last_name', 'email']
[(1, 'Ada', '', 'Lovelace', 'ada@example.com'), (2, 'Grace', '', 'Hopper', 'grace@example.com')]
La ejecución suministrada imprime el orden de las columnas y las filas que se muestran arriba. La salida presenta los nombres de las columnas y las filas de ejemplo; los nombres y valores visibles permanecen en inglés porque el bloque es idéntico al del original. Para los números de teléfono nuevos de los clientes existentes, el ejemplo usa una cadena vacía; sustituye esa expresión por un valor o una regla de migración adecuados para tus datos. La definición de la tabla y ambas listas de columnas son explícitas: así, la columna nueva queda en la posición prevista y cada valor anterior se asigna a su columna de destino correspondiente.
Copiar los datos existentes a la tabla reconstruida
La instrucción INSERT INTO ... SELECT copia filas de la tabla original. La lista de destino indica las columnas de la tabla de reemplazo, y la lista de SELECT proporciona los valores en el mismo orden. Aquí, phone_number no tiene una columna de origen, así que la consulta proporciona '' para las filas existentes. También puedes usar un valor predeterminado adecuado, un valor fijo o una transformación basada en los datos existentes. Decide cómo se rellenará la columna nueva antes de migrar, sobre todo si la restricción NOT NULL la hace obligatoria.
Evita SELECT *: la tabla antigua y la nueva tienen distintas distribuciones de columnas. Las listas explícitas aclaran la correspondencia e impiden que, al cambiar los esquemas, los valores terminen en columnas equivocadas.
Sustituir la tabla antigua y verificar el resultado
No elimines la tabla original hasta que la de reemplazo esté completa y tengas un plan de recuperación. Una tabla de producción también puede tener índices, desencadenadores, relaciones de clave foránea o vistas dependientes. Como parte de la migración, vuelve a crear los objetos de esquema necesarios y ten en cuenta las dependencias de claves foráneas; el ejemplo compacto no las modela. Haz una copia de seguridad de los datos importantes y realiza la reconstrucción dentro de una transacción adecuada al esquema que la rodea.
Después de sustituir la tabla, inspecciona el esquema con PRAGMA table_info(customers) y verifica algunas filas representativas con una consulta SELECT que nombre las columnas explícitamente. Comprueba también el número de filas y las restricciones u objetos dependientes relevantes para tu aplicación. Estas comprobaciones confirman que cambió el orden de las columnas y que se conservaron los valores originales y el comportamiento requerido del esquema.