MySQL Select en Python
Aprende a usar SELECT en Python con mysql-connector-python: obtén todas las filas, filas individuales, columnas específicas y usa fetchone vs fetchall.
La sentencia SELECT es la base de toda operación de lectura en una base de datos. En Python se ejecuta a través de un objeto cursor proporcionado por mysql-connector-python, y los resultados se recuperan con fetchall(), fetchone() o fetchmany(). Este capítulo cubre los tres métodos de recuperación, cómo seleccionar columnas específicas, cómo trabajar con nombres de columnas y los patrones de manejo de errores que necesitas en código de producción.
Requisitos previos
Instala el conector de MySQL si aún no lo has hecho:
pip install mysql-connector-pythonTodos los ejemplos asumen:
- Un servidor MySQL en ejecución (local o remoto).
- Una base de datos llamada
mydatabasecon una tablacustomersque tiene al menos las columnasid,nameyaddress.
Sigue Python MySQL Crear Tabla para crear la tabla, y Python MySQL Insert para poblarla con filas de ejemplo antes de ejecutar los ejemplos de SELECT a continuación.
Conexión a la base de datos
Cada ejemplo parte de un objeto de conexión. En lugar de repetir la configuración en cada fragmento, mantenla en un solo lugar y reutilízala:
import mysql.connector
from mysql.connector import Error
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)Reemplaza yourusername y yourpassword con tus credenciales reales. Consulta Python MySQL Primeros Pasos para saber cómo almacenar credenciales en variables de entorno en lugar de codificarlas directamente.
Seleccionar todas las filas con fetchall()
fetchall() recupera todas las filas devueltas por la consulta y las almacena en una lista Python de tuplas. Úsalo cuando el conjunto de resultados sea lo suficientemente pequeño para caber cómodamente en memoria.
Seleccionar todos los registros de la tabla customers
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Cada row es una tupla cuyos valores corresponden a las columnas de la tabla en el orden en que aparecen en la sentencia CREATE TABLE. Para una tabla customers con columnas (id, name, address) verías una salida similar a:
(1, 'John', '123 Main St')
(2, 'Susan', '456 Oak Ave')
(3, 'Maria', '789 Pine Rd')¿Por qué envolver todo en try/except/finally?
Si se lanza una excepción entre la apertura y el cierre de la conexión, la conexión queda abierta y consume recursos del servidor hasta que este la agota por tiempo de espera. El bloque finally garantiza que cursor.close() y connection.close() siempre se llamen, incluso cuando algo sale mal.
Seleccionar una sola fila con fetchone()
Cuando solo necesitas la primera fila coincidente — o sabes que la consulta devuelve exactamente un resultado — fetchone() es más eficiente que fetchall(). Devuelve una sola tupla o None si no hay resultados.
Recuperar una fila de la tabla customers
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
row = cursor.fetchone()
if row:
print("First customer:", row)
else:
print("No records found.")
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()fetchone() avanza el puntero interno del cursor. Llamarlo de nuevo devuelve la siguiente fila. Esto lo hace adecuado para iterar por los resultados fila a fila sin cargar todo el conjunto de resultados en memoria.
Seleccionar columnas específicas
Usar SELECT * devuelve todas las columnas de la tabla. Para tablas grandes o cuando solo necesitas algunos campos, nombra las columnas explícitamente. Esto reduce los datos transferidos por la red y hace que la intención de tu código sea clara.
Seleccionar solo las columnas name y address
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT name, address FROM customers")
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Salida (ejemplo):
('John', '123 Main St')
('Susan', '456 Oak Ave')
('Maria', '789 Pine Rd')Obtener filas en lotes con fetchmany()
fetchmany(size) recupera size filas a la vez. Úsalo cuando el conjunto de resultados sea demasiado grande para fetchall() pero aun así quieras procesar las filas en bloques en lugar de una a una.
Procesar resultados de 10 filas a la vez
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
batch_size = 10
while True:
rows = cursor.fetchmany(batch_size)
if not rows:
break
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()fetchmany() devuelve una lista vacía cuando no hay más filas, que es lo que detecta la comprobación if not rows: break.
Acceder a columnas por nombre con un cursor de diccionario
Por defecto, cada fila es una tupla simple. Si tienes muchas columnas, acceder a row[4] en lugar de row["email"] hace que el código sea difícil de leer y falla silenciosamente cuando cambia el orden de las columnas. Pasa dictionary=True al constructor del cursor para obtener cada fila como un dict en su lugar.
Usar un cursor de diccionario para acceso por nombre de columna
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
# dictionary=True makes each row a dict
cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT * FROM customers")
rows = cursor.fetchall()
for row in rows:
print(f"ID: {row['id']}, Name: {row['name']}, Address: {row['address']}")
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Salida:
ID: 1, Name: John, Address: 123 Main St
ID: 2, Name: Susan, Address: 456 Oak AveLos cursores de diccionario hacen que el código sea autodocumentado y resistente al reordenamiento de columnas.
Filtrar filas con WHERE
Para recuperar solo las filas que coinciden con una condición, agrega una cláusula WHERE. Utiliza siempre consultas parametrizadas — nunca formatees valores proporcionados por el usuario directamente en la cadena SQL, ya que eso abre la puerta a ataques de inyección SQL.
Recuperar clientes que viven en una calle específica
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
sql = "SELECT * FROM customers WHERE address = %s"
val = ("123 Main St",) # Always pass a tuple, even for a single value
cursor.execute(sql, val)
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()El marcador de posición %s es completado por el driver del conector, que escapa el valor de forma segura. Consulta Python MySQL Where para un tratamiento completo del filtrado, incluyendo múltiples condiciones con AND/OR.
Usar SELECT con ORDER BY y LIMIT
Combina SELECT con ORDER BY para ordenar los resultados y LIMIT para limitar el número de filas devueltas. Este patrón es esencial para mostrar los registros más recientes o implementar paginación.
Obtener los 3 clientes con los IDs más altos, ordenados del más reciente al más antiguo
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers ORDER BY id DESC LIMIT 3")
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Para una guía dedicada al ordenamiento, consulta Python MySQL Order By. Para paginación con OFFSET, consulta Python MySQL Limit.
Verificar los nombres de columnas con cursor.description
Después de llamar a execute(), el atributo description del cursor contiene metadatos sobre cada columna del resultado — incluyendo el nombre de la columna. Esto es útil cuando necesitas los nombres de las columnas de forma dinámica (por ejemplo, al construir una exportación CSV) sin codificarlos directamente.
Imprimir los nombres de columnas junto con los datos
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
# cursor.description is a list of 7-item sequences; index 0 is the column name
column_names = [desc[0] for desc in cursor.description]
print("Columns:", column_names)
rows = cursor.fetchall()
for row in rows:
print(dict(zip(column_names, row)))
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Salida (ejemplo):
Columns: ['id', 'name', 'address']
{'id': 1, 'name': 'John', 'address': '123 Main St'}
{'id': 2, 'name': 'Susan', 'address': '456 Oak Ave'}Elegir entre fetchall(), fetchone() y fetchmany()
| Método | Devuelve | Mejor para |
|---|---|---|
fetchall() | Lista de todas las tuplas | Conjuntos de resultados pequeños a medianos donde todas las filas se necesitan a la vez |
fetchone() | Una sola tupla o None | Búsqueda por clave primaria; iterar fila a fila |
fetchmany(n) | Lista de hasta n tuplas | Conjuntos de resultados grandes procesados en bloques de streaming |
Si llamas a fetchall() en un conjunto de resultados de un millón de filas, Python almacena el millón de tuplas en memoria al mismo tiempo. Para tablas grandes, usa fetchmany() o agrega una cláusula LIMIT a la consulta.
Errores comunes y cómo solucionarlos
| Error | Causa probable | Solución |
|---|---|---|
mysql.connector.errors.ProgrammingError: Table doesn't exist | El nombre de la tabla es incorrecto o la base de datos no fue seleccionada | Verifica el nombre de la tabla; asegúrate de que el parámetro database esté establecido en connect() |
mysql.connector.errors.InterfaceError: No result set | Llamar a fetchall() después de una sentencia que no es SELECT | Solo llama a los métodos fetch después de SELECT, SHOW u otras sentencias que producen resultados |
mysql.connector.errors.DatabaseError: Lost connection | Tiempo de espera de red o reinicio del servidor | Restablece la conexión; para aplicaciones de larga duración, usa un pool de conexiones |
InternalError: Unread result found | Iniciar un nuevo execute() antes de consumir los resultados anteriores | Llama a fetchall() o cursor.reset() para vaciar el conjunto de resultados anterior primero |
Resumen
- Ejecuta una sentencia
SELECTconcursor.execute("SELECT ..."). - Usa
fetchall()para conjuntos de resultados pequeños,fetchone()para una sola fila, yfetchmany(n)para grandes conjuntos de datos procesados en bloques. - Pasa
dictionary=Trueal cursor para acceder a las columnas por nombre en lugar de por índice. - Usa siempre marcadores de posición parametrizados
%sal filtrar con valores proporcionados por el usuario. - Envuelve cada operación de base de datos en
try/except/finallypara garantizar que la conexión se cierre en caso de error.
Capítulos relacionados
- Python MySQL Primeros Pasos — instala el driver y establece una conexión
- Python MySQL Crear Tabla — define el esquema de la tabla para tus consultas
- Python MySQL Insert — agrega filas antes de consultarlas
- Python MySQL Where — filtra los resultados de SELECT con condiciones
- Python MySQL Order By — ordena los resultados de SELECT
- Python MySQL Limit — restringe el número de filas devueltas
- Python MySQL Join — combina datos de múltiples tablas