W3docs

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-python

Todos los ejemplos asumen:

  • Un servidor MySQL en ejecución (local o remoto).
  • Una base de datos llamada mydatabase con una tabla customers que tiene al menos las columnas id, name y address.

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 Ave

Los 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étodoDevuelveMejor para
fetchall()Lista de todas las tuplasConjuntos de resultados pequeños a medianos donde todas las filas se necesitan a la vez
fetchone()Una sola tupla o NoneBúsqueda por clave primaria; iterar fila a fila
fetchmany(n)Lista de hasta n tuplasConjuntos 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

ErrorCausa probableSolución
mysql.connector.errors.ProgrammingError: Table doesn't existEl nombre de la tabla es incorrecto o la base de datos no fue seleccionadaVerifica el nombre de la tabla; asegúrate de que el parámetro database esté establecido en connect()
mysql.connector.errors.InterfaceError: No result setLlamar a fetchall() después de una sentencia que no es SELECTSolo llama a los métodos fetch después de SELECT, SHOW u otras sentencias que producen resultados
mysql.connector.errors.DatabaseError: Lost connectionTiempo de espera de red o reinicio del servidorRestablece la conexión; para aplicaciones de larga duración, usa un pool de conexiones
InternalError: Unread result foundIniciar un nuevo execute() antes de consumir los resultados anterioresLlama a fetchall() o cursor.reset() para vaciar el conjunto de resultados anterior primero

Resumen

  • Ejecuta una sentencia SELECT con cursor.execute("SELECT ...").
  • Usa fetchall() para conjuntos de resultados pequeños, fetchone() para una sola fila, y fetchmany(n) para grandes conjuntos de datos procesados en bloques.
  • Pasa dictionary=True al cursor para acceder a las columnas por nombre en lugar de por índice.
  • Usa siempre marcadores de posición parametrizados %s al filtrar con valores proporcionados por el usuario.
  • Envuelve cada operación de base de datos en try/except/finally para garantizar que la conexión se cierre en caso de error.

Capítulos relacionados

Was this page helpful?