Una sola conexión, varios archivos
Una conexión de SQLite no está atada a un único archivo. Con ATTACH DATABASE puedes abrir archivos .db adicionales junto al que ya tenías abierto y consultarlos como si fueran esquemas dentro de una misma base de datos. Es lo más parecido que ofrece SQLite a tener "varias bases de datos en un mismo servidor".
La sintaxis básica es la siguiente:
El archivo archive.db se crea si no existe, igual que ocurre con la base de datos principal. A partir de aquí, dentro de esta sesión, todo lo que lleve el prefijo archive. vive en ese segundo archivo, y todo lo que lleve main. (o vaya sin prefijo) sigue viviendo en el original.
Tu conexión siempre arrastra dos esquemas implícitos: main (el archivo que abriste primero) y temp (un espacio temporal para tablas auxiliares). Al adjuntar una base de datos, sumas más esquemas a esa lista.
Sintaxis de ATTACH DATABASE y para qué sirve el alias
ATTACH DATABASE 'ruta/al/archivo.db' AS nombre_alias;
El alias es el nombre de esquema que vas a usar para calificar las tablas. Es local a la conexión actual: otra conexión que adjunte el mismo archivo puede elegir un alias distinto. Conviene que sea corto y descriptivo (archive, analytics, cache), porque lo vas a escribir muchas veces.
Un par de cosas que vale la pena tener en cuenta:
- La ruta es relativa al directorio de trabajo del proceso, salvo que sea absoluta.
- La cadena
':memory:'adjunta una base de datos en memoria nueva bajo ese alias. - El alias no puede chocar con
mainnitemp, ni repetirse entre adjuntos.
Hacer JOIN entre bases SQLite
Esta es la razón por la que la mayoría recurre a ATTACH DATABASE. En cuanto tienes dos archivos dentro de la misma conexión, puedes hacer un join entre sus tablas en una sola consulta:
El planificador de consultas trata ambos esquemas igual que las tablas de main. Los índices de las tablas adjuntas se aprovechan sin problema. EXPLAIN QUERY PLAN funciona entre ellas. No hay ida y vuelta por red: los dos archivos están abiertos en el mismo proceso.
Esto resulta realmente útil para separar datos calientes de archivos históricos, aislar archivos por tenant o extraer datos de referencia desde una base de solo lectura.
Adjuntar bases en solo lectura y en memoria
Si la segunda base es algo que quieres leer pero nunca modificar —por ejemplo, un dataset de referencia que distribuyes con tu aplicación—, adjúntala en modo solo lectura usando una URI:
La forma URI requiere que la biblioteca SQLite tenga habilitado SQLITE_OPEN_URI (viene activado en la CLI y en la mayoría de bindings de cada lenguaje). Con esto, cualquier INSERT, UPDATE o DELETE sobre ref.* lanzará un error antes siquiera de tocar el archivo.
Adjuntar una base de datos en memoria resulta igual de útil para preparar datos temporales:
scratch desaparece al cerrar la conexión. Funciona como temp, pero el ciclo de vida lo controlas tú.
Las transacciones abarcan todas las bases adjuntas
Un único BEGIN/COMMIT cubre las escrituras tanto en main como en cualquier esquema adjunto. O se confirma todo, o se revierte todo: la atomicidad se mantiene aunque haya varios archivos de por medio.
Mover filas de una tabla viva a un archivo de archivado histórico es justo el caso donde te interesa esta garantía. Sin atomicidad entre archivos, una caída a mitad de la operación te dejaría con duplicados o, peor aún, con filas perdidas.
Un detalle a tener en cuenta: cuando una misma transacción escribe en más de una base adjunta, SQLite recurre a un protocolo de commit más prudente que necesita un journal temporal. Es más lento que un commit sobre un único archivo, pero igual de seguro.
Desadjuntar una base de datos
Cuando ya no necesites una base adjunta, suéltala:
DETACH DATABASE archive;
El archivo sigue intacto en el disco — DETACH simplemente cierra el handle en la conexión actual. Dos restricciones que conviene recordar:
- No puedes desadjuntar
mainnitemp. - No puedes desadjuntar una base de datos que esté dentro de una transacción o tenga sentencias abiertas contra ella.
Y si se te olvida hacer detach, tampoco pasa nada grave: al cerrar la conexión se limpia todo automáticamente.
Límites y errores frecuentes
Hay algunos límites prácticos que vale la pena tener presentes:
- El tope por defecto es de 10 bases de datos adjuntas por conexión (sin contar
mainytemp). El máximo en tiempo de compilación es 125. Si te pasas, verás el mensajetoo many attached databases - max 10. - Cada archivo adjunto consume su propia caché de páginas. Adjuntar una docena de bases grandes no sale gratis — la RAM sube.
ATTACHno se puede ejecutar dentro de una transacción. Hazlo antes delBEGIN, o después delCOMMIT.
Estos son algunos de los errores con los que te vas a topar:
-- El archivo no existe y el directorio no permite escritura:
Error: unable to open database: 'missing/path.db'
-- Intentaste escribir en un adjunto de solo lectura:
Error: attempt to write a readonly database
-- Usaste el mismo alias dos veces:
Error: database archive is already in use
La mayoría de estos errores se entienden a la primera. El que más despista es el de "alias ya en uso": ATTACH no reemplaza un alias existente, así que toca hacer DETACH antes.
Un patrón realista: separación hot/cold
Vamos a juntar todo lo visto en un mini flujo de archivado que mueve los pedidos con más de un año de antigüedad fuera de la base de datos principal:
Las filas antiguas se mueven a archive.orders y las recientes se quedan en main. Los reportes que necesitan histórico pueden hacer join entre ambas, mientras que las consultas del día a día contra main.orders siguen siendo rápidas porque la tabla es más pequeña. Una sola conexión, dos archivos, una transacción.
Lo que viene: sentencias preparadas
ATTACH se trata de darle a una misma conexión acceso a más datos. El siguiente bloque de temas va por otro lado: cómo las aplicaciones se comunican con SQLite de forma segura y eficiente. Arrancamos con las sentencias preparadas, la base del binding de parámetros y de las consultas a prueba de inyección SQL.
Preguntas frecuentes
¿Para qué sirve ATTACH DATABASE en SQLite?
ATTACH DATABASE 'archivo.db' AS alias abre un segundo archivo SQLite dentro de la conexión actual y le asigna un nombre de esquema. A partir de ahí puedes referenciar sus tablas como alias.nombre_tabla y combinarlas en una misma consulta con las de tu base principal.
¿Cuántas bases de datos puede adjuntar SQLite a la vez?
Por defecto, SQLite admite hasta 10 bases adjuntas por conexión, además de los esquemas main y temp. El tope absoluto es 125 y se ajusta en tiempo de compilación con SQLITE_MAX_ATTACHED. Si te pasas, recibirás un error too many attached databases.
¿Puedo consultar varias bases adjuntas en una sola sentencia?
Sí. Una vez adjuntas, basta con cualificar cada tabla con su esquema: SELECT * FROM main.users JOIN archive.orders ON .... Funcionan los JOIN, las subconsultas y los INSERT ... SELECT entre esquemas. Las transacciones también abarcan todas las bases adjuntas, así que un COMMIT es atómico entre archivos.
¿Cómo desadjunto una base de datos en SQLite?
Con DETACH DATABASE alias. El archivo permanece intacto en disco; DETACH solo cierra el handle en la conexión actual. No puedes desadjuntar main ni temp, ni una base que esté en mitad de una transacción.