Saltar al contenido principal

7.3.2 CRUD con SQLite

Una vez que tenemos nuestra estructura de tablas, necesitamos saber cómo interactuar con los datos. En el mundo de la persistencia, esto se resume en las siglas CRUD: Create (Crear), Read (Leer), Update (Actualizar) y Delete (Borrar).

Dominar estas cuatro operaciones es dominar la gestión de la información de cualquier aplicación profesional.


1️⃣ Insertar Datos (CREATE)​

Insertar datos no es solo meter texto en una tabla; es asegurar que la información entra de forma segura y eficiente.

🟩 Inserción segura con parámetros​

Nunca uses f-strings o concatenación para meter variables en una consulta SQL. Esto abre la puerta a ataques de "Inyección SQL". Usa siempre marcadores de posición (?).

nombre = "El Quijote"
autor = "Cervantes"
paginas = 863

cursor.execute(
"INSERT INTO libros (titulo, autor, paginas) VALUES (?, ?, ?)",
(nombre, autor, paginas)
)
ojo

Nota que los valores se pasan como una tupla en el segundo argumento de execute(). Si solo pasas un valor, debe ser (valor,).

🟦 Inserciones masivas con executemany()​

Si tienes una lista de cientos de registros, llamar a execute() en un bucle es muy lento (por el overhead de comunicación con el motor). executemany() está optimizado para esto.

nuevos_libros = [
("Moby Dick", "Herman Melville", 635),
("1984", "George Orwell", 328),
("Drácula", "Bram Stoker", 418)
]

cursor.executemany(
"INSERT INTO libros (titulo, autor, paginas) VALUES (?, ?, ?)",
nuevos_libros
)

2️⃣ Consultar Datos (READ)​

Extraer información es la operación más común. SQLite nos ofrece varias formas de "recoger" los resultados que devuelve el cursor.

🟩 El cursor como iterador​

Para archivos grandes, lo más eficiente es recorrer el cursor directamente.

cursor.execute("SELECT titulo, autor FROM libros")

for fila in cursor:
print(f"Libro: {fila[0]} - Autor: {fila[1]}")

🟦 fetchone() y fetchall()​

  • fetchone(): Devuelve la siguiente fila o None si no hay más. Ideal para búsquedas por ID.
  • fetchall(): Devuelve una lista con todas las filas. Cuidado: carga todo en la memoria RAM.
cursor.execute("SELECT * FROM libros WHERE id = ?", (1,))
libro = cursor.fetchone()

if libro:
print(f"Encontrado: {libro['titulo']}")
Recordatorio

Si activaste conn.row_factory = sqlite3.Row en la conexión, podrás acceder por nombre de columna: libro['titulo']. Si no, tendrás que usar índices: libro[1].


3️⃣ Actualizar y Borrar (UPDATE & DELETE)​

Estas operaciones son potentes pero peligrosas. Un error en la cláusula WHERE puede vaciar o estropear toda una tabla.

🟩 Actualización selectiva​

# Cambiar el estado de un libro específico
cursor.execute(
"UPDATE libros SET estado = ? WHERE id = ?",
("prestado", 15)
)

🟦 Borrado de registros​

# Eliminar libros muy cortos
cursor.execute("DELETE FROM libros WHERE paginas < ?", (50,))

🟨 cursor.rowcount: ¿Ha pasado algo?​

A veces ejecutas un UPDATE pero no se actualiza nada (porque el ID no existía, por ejemplo). rowcount te dice cuántas filas se han visto afectadas.

cursor.execute("DELETE FROM libros WHERE autor = ?", ("Desconocido",))
print(f"Se han eliminado {cursor.rowcount} libros.")

✅ Reglas de Oro del CRUD​

resumen profesional
  1. Siempre con WHERE: En Updates y Deletes, asegúrate de que tu filtro es correcto antes de ejecutar.
  2. Commit es obligatorio: Si no haces commit() (manualmente o mediante un with), tus INSERTS, UPDATES y DELETES desaparecerán al cerrar la conexión.
  3. Parámetros siempre: Los ? no son opcionales en código profesional. Nunca metas variables directamente en el string del SQL.

🧪 Ejercicios prácticos – Misión: La Cripta de Datos (Parte 2)​

La biblioteca secreta ya tiene su base de datos. Ahora el bibliotecario necesita que empieces a gestionar los tomos antiguos.

🟢 Fase 1 – El Gran Ingreso​

🟩 Ejercicio 1 – El Primer Manuscrito​

Inserta un libro titulado "Necronomicón", de "Abdul Alhazred", con 666 páginas. Asegúrate de hacer commit().

🟦 Ejercicio 2 – La Caravana de Libros​

Tienes una lista de libros que acaba de llegar:

lote = [
("Fundación", "Isaac Asimov", 255),
("El Hobbit", "J.R.R. Tolkien", 310),
("Neuromante", "William Gibson", 271)
]

Insértalos todos de una sola vez usando la función más eficiente.

🟨 Ejercicio 3 – Importación Masiva (CSV)​

En la carpeta de recursos tienes el archivo biblioteca_inicial.csv. Crea un script que lea este archivo y vuelque todos sus libros en la base de datos biblioteca_secreta.db. (Pista: necesitarás combinar el módulo csv que aprendimos en el bloque anterior con executemany)

🟡 Fase 2 – Auditoría de Estanterías​

🟧 Ejercicio 4 – El Buscador​

Pide al usuario un nombre de autor por teclado. Busca en la base de datos todos los libros de ese autor y muéstralos por pantalla. Si no hay ninguno, avisa al usuario.

🟫 Ejercicio 5 – Espacio en las estanterías​

El bibliotecario decide que los libros de menos de 100 páginas no son "tomos reales" y deben ser eliminados de la base de datos de la biblioteca secreta. Realiza el borrado y muestra por pantalla cuántos registros se han eliminado usando rowcount.

🔴 Fase 3 – Mantenimiento Preventivo​

🟥 Ejercicio 5 – Restauración de Tomos​

Se ha descubierto que todos los libros de "Isaac Asimov" deben marcarse con el estado 'en restauración'. Actualiza sus registros y verifica que el cambio se ha realizado correctamente consultando de nuevo la base de datos.

🟪 Ejercicio 6 – El Informe de la Cripta​

Genera un informe por consola que muestre:

  1. El título del libro más largo de la biblioteca.
  2. El número total de libros registrados actualmente. (Pista: puedes usar funciones SQL como MAX() y COUNT() o procesar los datos con Python tras un SELECT *)