Si has trabajado con datos en Python, seguro que en algún momento has pensado: "necesito una base de datos, pero montar PostgreSQL o MySQL para esto es una exageración". Para esos casos existe SQLite, y combinado con Python es una de las herramientas más útiles que puedes tener en tu cinturón.
SQLite no es un sistema cliente-servidor como otros motores de bases de datos. No tienes que instalar un servicio, abrir puertos, crear usuarios ni gestionar conexiones. Tu programa habla directamente con un archivo, y ese archivo es la base de datos. Literalmente.
En esta guía vas a aprender a usar SQLite desde Python paso a paso: crear tablas, insertar datos, consultarlos, actualizarlos y, lo más importante, evitar los errores más comunes que cometemos todos al empezar.
¿Qué es SQLite y por qué usarlo con Python?
SQLite es una biblioteca en C que implementa un motor de base de datos SQL embebido. A diferencia de PostgreSQL o MySQL, no hay un proceso separado ejecutándose en segundo plano. Cuando tu programa Python abre una base de datos SQLite, está leyendo y escribiendo directamente sobre un archivo .db o .sqlite.
Python incluye SQLite en su biblioteca estándar desde hace décadas. No necesitas instalar nada, no necesitas pip install. Solo importas sqlite3 y ya tienes un motor de base de datos listo para usar.
Esto la hace ideal para:
- Aplicaciones de escritorio que necesitan persistencia local
- Prototipos y herramientas internas que no justifican un servidor
- Scripts de análisis de datos donde los CSV se quedan cortos
- Pruebas y desarrollo antes de migrar a una base de datos más potente
- Aplicaciones móviles (de hecho, SQLite es el motor por defecto en Android e iOS)
La principal limitación a tener en cuenta: SQLite no está diseñada para alto volumen de escrituras concurrentes. Si esperas cien usuarios escribiendo a la vez, no es tu herramienta. Para todo lo demás, funciona de maravilla.
Conexión y creación de base de datos
El primer paso es siempre el mismo: conectarse. Si el archivo de base de datos no existe, SQLite lo crea automáticamente:
import sqlite3
conexion = sqlite3.connect("mi_biblioteca.db")
cursor = conexion.cursor()
Eso es todo. Ya tienes una base de datos abierta y un cursor para ejecutar consultas. Cuando termines, cierras la conexión:
conexion.close()
Pero hay un detalle importante que te ahorrará dolores de cabeza: SQLite opera en modo transaccional por defecto. Esto significa que los cambios no se guardan en disco hasta que haces commit(). Si tu programa se cierra inesperadamente sin hacer commit, pierdes los datos de esa sesión.
# Esto guarda los cambios pendientes
conexion.commit()
También existe el modo autocommit, que puedes activar pasando autocommit=True al conectar (disponible desde Python 3.12). Pero para la mayoría de los casos, el control manual de transacciones es más seguro.
Crear tablas
Crear una tabla en SQLite desde Python es tan sencillo como ejecutar una sentencia CREATE TABLE:
cursor.execute("""
CREATE TABLE IF NOT EXISTS libros (
id INTEGER PRIMARY KEY AUTOINCREMENT,
titulo TEXT NOT NULL,
autor TEXT NOT NULL,
ano_publicacion INTEGER,
paginas INTEGER,
genero TEXT,
leido BOOLEAN DEFAULT 0,
fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
conexion.commit()
La cláusula IF NOT EXISTS evita que el script falle si ya ejecutaste este código antes. Es una buena práctica incluirla siempre.
SQLite soporta los tipos de datos más comunes: INTEGER, TEXT, REAL, BLOB y BOOLEAN (que internamente se almacena como entero 0 o 1). El TIMESTAMP también se guarda como texto, pero SQLite tiene funciones para trabajar con fechas.
Insertar datos
Para insertar datos tienes dos opciones. La primera, usando cadenas con formato, es la que debes evitar:
# ❌ MAL: vulnerable a inyección SQL
cursor.execute(f"INSERT INTO libros VALUES (NULL, '{titulo}', '{autor}', ...)")
La segunda, usando parámetros con ?, es la correcta:
# ✅ BIEN: parámetros seguros
cursor.execute(
"INSERT INTO libros (titulo, autor, ano_publicacion, paginas, genero, leido) VALUES (?, ?, ?, ?, ?, ?)",
("Cien años de soledad", "Gabriel García Márquez", 1967, 417, "Novela", 1)
)
conexion.commit()
Los ? son marcadores de posición. SQLite se encarga de escapar los valores correctamente, evitando inyección SQL y problemas con caracteres especiales.
Para insertar varios registros a la vez, usa executemany() con una lista de tuplas:
varios_libros = [
("1984", "George Orwell", 1949, 328, "Distopía", 1),
("Dune", "Frank Herbert", 1965, 688, "Ciencia ficción", 1),
("El nombre del viento", "Patrick Rothfuss", 2007, 662, "Fantasía", 0),
]
cursor.executemany(
"INSERT INTO libros (titulo, autor, ano_publicacion, paginas, genero, leido) VALUES (?, ?, ?, ?, ?, ?)",
varios_libros
)
conexion.commit()
executemany es mucho más rápido que insertar en un bucle, porque SQLite optimiza las inserciones múltiples en una sola operación.
$ python3 insertar_libros.py
Insertando 3 libros...
✓ 1984 — George Orwell (1949)
✓ Dune — Frank Herbert (1965)
✓ El nombre del viento — Patrick Rothfuss (2007)
3 libros insertados en 0.002s usando executemany()
Consultar datos
Para recuperar datos, ejecutas un SELECT y luego usas fetchone(), fetchall() o fetchmany():
cursor.execute("SELECT * FROM libros")
todos = cursor.fetchall()
for libro in todos:
print(libro)
Cada fila es una tupla con los valores en el orden de las columnas:
(1, 'Cien años de soledad', 'Gabriel García Márquez', 1967, 417, 'Novela', 1, '2026-07-23')
Pero trabajar con tuplas por índice numérico no es muy legible. Puedes configurar el cursor para que devuelva diccionarios:
conexion.row_factory = sqlite3.Row
cursor.execute("SELECT titulo, autor, paginas FROM libros WHERE leido = ?", (1,))
for fila in cursor.fetchall():
print(f"{fila['titulo']} de {fila['autor']} — {fila['paginas']} páginas")
Esto hace que el código sea mucho más claro, sobre todo cuando trabajas con muchas columnas.
Las consultas con filtros, ordenación y límites funcionan como esperarías:
# Los 5 libros más largos que no has leído
cursor.execute(
"SELECT titulo, autor, paginas FROM libros WHERE leido = 0 ORDER BY paginas DESC LIMIT 5"
)
Actualizar y eliminar registros
Actualizar datos sigue el mismo patrón con parámetros:
cursor.execute(
"UPDATE libros SET leido = ?, fecha_lectura = CURRENT_TIMESTAMP WHERE id = ?",
(1, 3)
)
conexion.commit()
print(f"Filas actualizadas: {cursor.rowcount}")
La propiedad rowcount te dice cuántas filas se vieron afectadas por la última operación. Es muy útil para verificar que tu UPDATE o DELETE hizo lo que esperabas.
Para eliminar:
cursor.execute("DELETE FROM libros WHERE id = ?", (5,))
conexion.commit()
Precaución: un DELETE sin WHERE borra toda la tabla. Siempre revisa tu WHERE antes de ejecutar.
Trabajar con transacciones
Una de las características más potentes de SQLite es el soporte de transacciones. Puedes agrupar varias operaciones y confirmarlas todas juntas, o deshacerlas si algo falla:
try:
cursor.execute("INSERT INTO libros (titulo, autor) VALUES (?, ?)", ("El hobbit", "J.R.R. Tolkien"))
cursor.execute("UPDATE libros SET paginas = 310 WHERE titulo = ?", ("El hobbit",))
conexion.commit()
print("Transacción completada")
except Exception as e:
conexion.rollback()
print(f"Error, cambios deshechos: {e}")
Si algo falla durante la transacción, rollback() devuelve la base de datos al estado anterior. Esto evita que te queden datos a medio insertar o inconsistencias.
Usar la base de datos como gestor de contexto
Python permite usar sqlite3.Connection como gestor de contexto, lo que simplifica mucho la limpieza:
with sqlite3.connect("mi_biblioteca.db") as con:
con.row_factory = sqlite3.Row
cursor = con.cursor()
cursor.execute("SELECT titulo, autor FROM libros WHERE genero = ?", ("Fantasía",))
for fila in cursor.fetchall():
print(f"{fila['titulo']} — {fila['autor']}")
El gestor de contexto cierra la conexión automáticamente al salir del bloque. Pero ojo: no hace commit por ti. Si haces cambios dentro del bloque, necesitas llamar a con.commit() explícitamente antes de salir.
Errores comunes y cómo evitarlos
Olvidar el commit: el más frecuente con diferencia. Haces un INSERT, todo parece funcionar, cierras el programa y los datos no están. Solución: acostúmbrate a llamar a commit() después de cada operación de escritura.
No cerrar la conexión: si tu programa se ejecuta durante horas y abres conexiones sin cerrarlas, puedes acabar con bloqueos en el archivo de base de datos. Usa el gestor de contexto o llama a close() explícitamente.
Confundir execute con executemany: execute espera una sola consulta. executemany espera una consulta con parámetros y una lista de valores. Usar execute con una lista no funciona y tampoco da un error claro.
Asumir que los IDs son consecutivos: SQLite no reutiliza IDs automáticamente. Si borras la fila 5, la siguiente inserción usará el 6, no el 5. Esto no suele ser un problema, pero si necesitas IDs sin huecos, no confíes en AUTOINCREMENT para eso.
Usar cadenas formateadas para SQL: ya lo hemos dicho, pero merece repetirse: nunca hagas f"SELECT * FROM usuarios WHERE nombre = '{nombre}'". Usa siempre parámetros con ?.
Resumen y próximos pasos
En esta guía has aprendido a usar SQLite con Python desde cero: conectar, crear tablas, insertar, consultar, actualizar y borrar datos, siempre usando parámetros seguros y transacciones.
SQLite es una herramienta increíblemente útil que tienes instalada en Python sin hacer nada. Para aplicaciones de escritorio, scripts personales, prototipos y herramientas internas, es la opción correcta el 90% de las veces.
Si quieres seguir profundizando, estos son los siguientes temas que merece la pena explorar:
- Índices: cómo acelerar consultas en tablas grandes con
CREATE INDEX. - Vistas: crear consultas reutilizables como si fueran tablas virtuales.
- Funciones SQL personalizadas: registrar funciones Python para usarlas dentro de SQLite.
- Backup y migraciones: cómo hacer copias de seguridad y evolucionar el esquema sin perder datos.
El código completo de esta guía y ejemplos adicionales están disponibles para que los pruebes en tu propio equipo. Solo necesitas Python, que ya lo tienes.