PROGRAMACIÓN EN PYTHON – CLASE 12

(Creado por el analista de sistemas y docente Leonel Iván Saafigueroa)


BASE DE DATOS

Concepto y utilidad de los módulos en Python.


Imaginá que tenés una enorme colección de información, desde los productos de tu tienda hasta los datos de tus clientes. Para organizar y acceder a toda esa información de forma eficiente, usamos las bases de datos. En esencia, una base de datos es un sistema que permite almacenar, gestionar y acceder a datos de forma estructurada, posee estas ventajas:

  • Permite almacenar información de forma permanente.
  • Proporciona mecanismos para realizar búsquedas, actualizaciones y borrado de datos.
  • Organiza la información en tablas, con campos y registros.
  • Puede utilizar campos clave para facilitar las búsquedas.

La Estructura Fundamental


La base de datos organiza la información en tablas. Pensá en una tabla como una hoja de cálculo avanzada.

Cada tabla tiene:

Filas (Registros): Cada fila representa una entrada única o registro de la información, como un producto específico en tu inventario, un cliente en tu lista de contactos, o una entrada en un catálogo.

Columnas (Campos): Cada columna representa un campo específico de información sobre el registro. Por ejemplo, en la tabla de productos, podrías tener columnas para el nombre del producto, la descripción, el precio, y la cantidad de stock.

Ejemplo Práctico: La Tabla de Productos

ID ProductoNombreDescripciónPrecioStock
1Laptop GamerPotente para juegos120025
2Monitor 27″Alta resolución35030
3Teclado MecánicoCon switches mecánicos80 80
4Mouse ópticoMouse para diseño3090

Esta estructura facilita la búsqueda, el filtrado y la modificación de datos.



En una base de datos, un campo es una columna dentro de una tabla que almacena un tipo específico de información sobre los registros que están en esa tabla. Por ejemplo, si pensamos en una tabla de productos, cada producto sería un registro, y cada campo almacenaría una característica específica de ese producto, como su nombre, cantidad o precio.

Ejemplo Práctico: La Tabla de Productos

ID ProductoNombreDescripciónPrecioStock
1Laptop GamerPotente para juegos120025
2Monitor 27″Alta resolución35030
3Teclado MecánicoCon switches mecánicos80 80
4Mouse ópticoMouse para diseño3090

Por ejemplo, la fila 4 muestra el registro “Mouse Para diseño“, del campo representado por la columna Descripción.



Estos son algunos de los tipos de datos más comunes y útiles para un proyecto de gestión de inventario:

  • Texto: Este tipo de dato se utiliza para almacenar cadenas de texto. Por ejemplo, para guardar el nombre del producto (“Manzana“, “Leche“, etc.) o su descripción.
  • Números enteros: Es ideal para cantidades de productos o para campos que necesiten valores numéricos sin decimales, como el código de un producto.
  • Números de punto flotante: Ideal para almacenar precios o valores que incluyan decimales.
  • Fechas y horas: Ideales para registrar cuándo ocurrió algo, como la fecha en que un producto fue agregado al inventario.


El campo clave, también conocido como clave primaria, se utiliza para identificar de manera única cada registro. Permite diferenciar cada producto de manera única. Posee dos características principales:

Unicidad: No puede haber dos registros en la tabla que tengan el mismo valor en el campo clave. Por ejemplo, en nuestra tabla de productos, usamos un campo llamado “ID Producto“, que asigna un número único a cada producto. Así, aunque tengamos dos productos llamados “Pan“, cada uno tendría un número de ID diferente, lo que nos permite diferenciarlos.
No puede ser nulo: El campo clave debe tener siempre un valor. No puede quedar vacío. Si no existiera una clave para un registro, no tendríamos manera de identificarlo claramente dentro de la tabla.



Cada producto se puede almacenar dentro de un diccionario llamado inventario.

inventario = {
   1: {
       "nombre": "Manzana",
       "descripcion": "Fruta fresca y deliciosa",
       "cantidad": 50,
       "precio": 0.5,
       "categoria": "Frutas"
   }
}

A partir de lo que hemos aprendido, podríamos reemplazar ese diccionario por una tabla.

PRIMARY KEY indica que ese campo no admite duplicados.


NOT NULL indica que el campo no puede quedar vacío.


AUTOINCREMENT hace que el ID se asigne automáticamente cada vez que se registra un nuevo producto.

CampoTipo de datoPropiedades
ID ProductoINTEGERPRIMARY KEY, AUTOINCREMENT
NombreTEXTNOT NULL
DescripciónTEXT
CantidadINTEGERNOT NULL
PrecioREALNOT NULL
CategoríaTEXT

¿Qué es SQLite y para qué sirve?


SQLite es una biblioteca que proporciona un motor de base de datos SQL ligero, autónomo y sin servidor. Imaginá tener una base de datos completa en un solo archivo, que puedes llevar con vos a cualquier parte, sin necesidad de instalar un servidor de base de datos adicional.

¡Esa es la magia de SQLite!


Para acceder a las funciones de SQLite en Python, solo tenemos que importar el módulo sqlite3 usando la misma sintaxis que empleamos para otros módulos.

import sqlite3                   # Importar el módulo

Una vez que importamos sqlite3, podemos usar todas sus funciones y objetos para conectarnos a una base de datos, ejecutar consultas y almacenar o recuperar datos.



Luego de importar el módulo, usamos la función sqlite3.connect() para conectarnos (o crear una base de datos nueva si no existe). Al conectar con la base de datos, creamos un “puente” entre nuestro programa y el archivo de base de datos.

import sqlite3   # Importar el módulo
conexion = sqlite3.connect("inventario.db") # Conectar a la base de datos (o crearla)
cursor = conexion.cursor()       # Crear un cursor para interactuar con la base de datos

El cursor nos permite ejecutar comandos SQL para interactuar con la base de datos, como crear tablas y gestionar los datos que vamos a guardar.



La consulta SELECT nos permite obtener todos los registros de una tabla o sólo algunos en particular, según los filtros o condiciones que le indiquemos:

import sqlite3                              # Importar el módulo
conexion = sqlite3.connect("base_datos.db") # Conectarse a la base de datos
cursor = conexion.cursor()                  # Crear un cursor
cursor.execute("SELECT * FROM Personas")    # Ejecutar la consulta SELECT 
resultados = cursor.fetchall()              # Obtener todos los registros
for registro in resultados:                 # Mostrar los resultados  
   print("Nombre:", registro[0], "Edad:", registro[1], "Ciudad:", registro[2])
conexion.close()                             # Cerrar la conexión


Usando la cláusula WHERE, podemos definir una condición o filtro. Supongamos que queremos ver sólo los registros de personas que viven en “Buenos Aires“. En este caso, la consulta se ve así:

import sqlite3                              # Importar el módulo
conexion = sqlite3.connect("base_datos.db") # Conectarse a la base de datos
cursor = conexion.cursor()                  # Crear un cursor
# Ejecutar la consulta SELECT: 
cursor.execute("SELECT * FROM Personas WHERE ciudad = 'Buenos Aires'")    resultados = cursor.fetchall()              # Obtener todos los registros
for registro in resultados:                 # Mostrar los resultados  
   print("Nombre:", registro[0], "Edad:", registro[1], "Ciudad:", registro[2])
conexion.close()                             # Cerrar la conexión


Si en lugar de * ponemos el nombre de los campos que queremos recuperar, SELECT devuelve sólo estos datos. Por ejemplo, si solo queremos ver el nombre y la edad de cada persona usamos:

import sqlite3                              # Importar el módulo
conexion = sqlite3.connect("base_datos.db") # Conectarse a la base de datos
cursor = conexion.cursor()                  # Crear un cursor
# Ejecutar la consulta SELECT, devolviendo solo las columnas nombre y edad: 
cursor.execute("SELECT nombre, edad FROM Personas")   
resultados = cursor.fetchall()              # Obtener todos los registros
for registro in resultados:                 # Mostrar los resultados  
   print("Nombre:", registro[0], "Edad:", registro[1], "Ciudad:", registro[2])
conexion.close()                             # Cerrar la conexión


La cláusula ORDER BY ordena los resultados de una consulta alfabéticamente en orden creciente. Si usamos “DESC“, el orden se invierte. Podés probar el siguiente código:

import sqlite3                              # Importar el módulo
conexion = sqlite3.connect("base_datos.db") # Conectarse a la base de datos
cursor = conexion.cursor()                  # Crear un cursor
# Ejecutar la consulta SELECT, ordenada por nombre de "Z" a "A": 
cursor.execute("SELECT * FROM Personas ORDER BY nombre DESC;")   
resultados = cursor.fetchall()              # Obtener todos los registros
for registro in resultados:                 # Mostrar los resultados  
   print("Nombre:", registro[0], "Edad:", registro[1], "Ciudad:", registro[2])
conexion.close()                             # Cerrar la conexión


El comando INSERT permite agregar nuevos datos a una tabla. Es necesario especificar tanto los campos en los que queremos añadir datos como los valores que queremos almacenar en esos campos:

import sqlite3                              # Importar el módulo
conexion = sqlite3.connect("base_datos.db") # Conectarse a la base de datos
cursor = conexion.cursor()                  # Crear un cursor
# Insertar un nuevo registro en la tabla Personas
cursor.execute("INSERT INTO Personas (nombre, edad, ciudad) VALUES ('Carlos', 27, 'Tucumán')")
conexion.commit()                            # Guardar los cambios
conexion.close()                             # Cerrar la conexión


En SQLite (y en la mayoría de los sistemas de gestión de bases de datos), cuando llevás adelante operaciones como cursor.execute para insertar, actualizar o eliminar datos, dichas modificaciones no se guardan inmediatamente. En su lugar, los cambios se mantienen en una transacción.

Una transacción es un conjunto de operaciones que se ejecutan de forma “temporal” hasta que decidís confirmarlas o descartarlas. SQLite mantiene estas operaciones en memoria (buffer) o en un archivo temporal y no las aplica al archivo de la base de datos hasta que se haga un commit.



El comando UPDATE permite modificar datos que ya están guardados en una tabla. Podemos actualizar uno o varios campos de un registro específico sin necesidad de agregar un nuevo registro.

import sqlite3                              # Importar el módulo
conexion = sqlite3.connect("base_datos.db") # Conectarse a la base de datos
cursor = conexion.cursor()                  # Crear un cursor
# Actualizar la edad de Ana en la tabla Personas
cursor.execute("UPDATE Personas SET edad = 24 WHERE nombre = 'Ana'")

conexion.commit()                            # Guardar los cambios
conexion.close()                             # Cerrar la conexión


Finalmente, el comando DELETE en SQL nos permite eliminar registros de una tabla. Es importante recordar usar la cláusula WHERE para indicar la condición que deben cumplir los registros a eliminar.

import sqlite3                              # Importar el módulo
conexion = sqlite3.connect("base_datos.db") # Conectarse a la base de datos
cursor = conexion.cursor()                  # Crear un cursor
# Eliminar los registros con nombre "José" en la tabla Personas:
cursor.execute("DELETE FROM Personas WHERE nombre = 'José'")

conexion.commit()                            # Guardar los cambios
conexion.close()                             # Cerrar la conexión

TAREA PARA EL HOGAR

Crea un programa en Python que inserte varios registros en la tabla Personas usando una lista de tuplas predefinida. Cada tupla debe contener un nombre, una edad y una ciudad.

Usá un bucle para recorrer la lista e insertar cada persona en la base de datos. La lista debe tener al menos cinco personas nuevas y al finalizar el programa deben mostrarse todos los registros en la tabla Personas.

nuevas_personas = [
   ("Esteban", 32, "Mar del Plata"),
   ("Valeria", 27, "Bahía Blanca"),
   ("Fernando", 41, "Rosario"),
   ("Carolina", 29, "La Plata"),
   ("Juan", 35, "Córdoba")
]

Luego desarrollá un programa en Python que elimine todos los registros en la tabla Personas donde la edad sea menor a 25 años.

Al final del programa, mostrá todos los registros restantes para confirmar que se han eliminado correctamente aquellos que cumplen con la condición establecida.