MySQL Where
Aprende a usar la cláusula WHERE de MySQL en Python con consultas parametrizadas, operadores de comparación, LIKE, IN, BETWEEN, comprobaciones NULL y condiciones compuestas.
La cláusula WHERE es la forma principal de filtrar filas en una instrucción MySQL SELECT, UPDATE o DELETE. Este capítulo muestra cómo usarla desde Python con mysql-connector-python, abarcando filtros de una sola condición, operadores de comparación, LIKE, IN, BETWEEN, comprobaciones de NULL y lógica compuesta con AND/OR — todo utilizando consultas parametrizadas para prevenir la inyección SQL.
Requisitos previos
Asegúrate de tener lo siguiente antes de ejecutar los ejemplos:
- Python 3.x y un servidor MySQL en ejecución.
mysql-connector-pythoninstalado:
pip install mysql-connector-python- Una base de datos con una tabla
customersya creada — consulta MySQL Create Database y MySQL Create Table si aún no las has configurado.
Los ejemplos asumen esta tabla y algunas filas de muestra:
CREATE TABLE IF NOT EXISTS customers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address VARCHAR(255),
age INT
);
INSERT INTO customers (name, address, age) VALUES
('Alice', 'Oak Avenue 1', 30),
('Bob', 'Pine Street 42', 25),
('Charlie', 'Maple Road 7', 35),
('Diana', 'Oak Avenue 3', 28),
('Eve', NULL, 22);Por qué usar consultas parametrizadas
Antes de cualquier ejemplo de código, una regla: nunca construyas una condición WHERE concatenando cadenas suministradas por el usuario directamente en tu SQL. Este patrón es peligroso:
# NEVER do this — SQL injection risk
name = input("Enter name: ")
sql = "SELECT * FROM customers WHERE name = '" + name + "'"Si un usuario introduce ' OR '1'='1, la consulta devuelve todas las filas. En su lugar, siempre pasa los valores a través de la interfaz parametrizada de mysql-connector-python:
sql = "SELECT * FROM customers WHERE name = %s"
mycursor.execute(sql, (name,))El conector escapa el valor de forma segura antes de que llegue a la base de datos. El marcador de posición siempre es %s independientemente del tipo de dato de la columna (entero, string, fecha, etc.).
Filtrar por un valor exacto
El caso de uso más común: recuperar filas donde una columna es igual a un valor específico.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "SELECT * FROM customers WHERE name = %s"
val = ("Alice",)
mycursor.execute(sql, val)
results = mycursor.fetchall()
for row in results:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
(1, 'Alice', 'Oak Avenue 1', 30)Ten en cuenta que val debe ser una tupla incluso cuando solo hay un valor — de ahí la coma final en ("Alice",).
Operadores de comparación
La cláusula WHERE admite todos los operadores de comparación estándar de SQL:
| Operador | Significado | Condición de ejemplo |
|---|---|---|
= | Igual | age = 30 |
<> o != | Distinto | age <> 30 |
> | Mayor que | age > 25 |
>= | Mayor o igual que | age >= 28 |
< | Menor que | age < 30 |
<= | Menor o igual que | age <= 30 |
Ejemplo: Filas donde age es mayor que 28
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "SELECT name, age FROM customers WHERE age > %s"
val = (28,)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
('Alice', 30)
('Charlie', 35)Coincidencia de patrones con LIKE
LIKE hace coincidir patrones dentro de columnas de tipo string. Hay dos caracteres comodín disponibles:
%— coincide con cero o más caracteres._— coincide con exactamente un carácter.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Find customers whose address starts with "Oak"
sql = "SELECT name, address FROM customers WHERE address LIKE %s"
val = ("Oak%",)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
('Alice', 'Oak Avenue 1')
('Diana', 'Oak Avenue 3')LIKE no distingue mayúsculas de minúsculas en columnas utf8mb4 por defecto. Usa LIKE BINARY si necesitas una coincidencia sensible a mayúsculas y minúsculas.
Coincidencia de múltiples valores con IN
IN comprueba si el valor de una columna aparece en una lista. Es equivalente a encadenar múltiples condiciones OR, pero mucho más legible.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
names = ("Alice", "Charlie", "Eve")
# Build one %s placeholder per value
placeholders = ", ".join(["%s"] * len(names))
sql = f"SELECT name, age FROM customers WHERE name IN ({placeholders})"
mycursor.execute(sql, names)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
('Alice', 30)
('Charlie', 35)
('Eve', 22)Dado que el número de valores en IN puede variar en tiempo de ejecución, el patrón anterior construye la cadena de marcadores de posición de forma dinámica (", ".join(["%s"] * len(names))). Esto mantiene la parametrización intacta independientemente de la longitud de la lista.
Filtrado por rango con BETWEEN
BETWEEN selecciona filas donde el valor de una columna cae dentro de un rango inclusivo:
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "SELECT name, age FROM customers WHERE age BETWEEN %s AND %s"
val = (25, 30)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
('Alice', 30)
('Bob', 25)
('Diana', 28)BETWEEN 25 AND 30 incluye ambos valores extremos (25 y 30). Funciona con fechas y strings además de con números.
Verificar valores NULL
Un valor NULL significa que el campo no tiene datos. No puedes comprobar NULL con = — debes usar IS NULL o IS NOT NULL.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Find customers with no address recorded
sql = "SELECT name FROM customers WHERE address IS NULL"
mycursor.execute(sql)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
('Eve',)IS NULL e IS NOT NULL no toman parámetros, por lo que no se pasa un segundo argumento a execute().
Condiciones compuestas con AND y OR
Combina múltiples condiciones en una cláusula WHERE usando AND (todas las condiciones deben ser verdaderas) y OR (al menos una condición debe ser verdadera).
Ejemplo con AND
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Customers on "Oak Avenue" who are older than 28
sql = "SELECT name, address, age FROM customers WHERE address LIKE %s AND age > %s"
val = ("Oak%", 28)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
('Alice', 'Oak Avenue 1', 30)Diana vive en Oak Avenue pero tiene 28 años, por lo que no satisface age > 28.
Ejemplo con OR
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Customers named Alice OR younger than 25
sql = "SELECT name, age FROM customers WHERE name = %s OR age < %s"
val = ("Alice", 25)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
('Alice', 30)
('Eve', 22)Usa paréntesis para controlar la precedencia al mezclar AND y OR: (a OR b) AND c se comporta de manera diferente a a OR (b AND c).
Usar WHERE con UPDATE y DELETE
La cláusula WHERE es igualmente crítica en las instrucciones UPDATE y DELETE. Sin ella, la instrucción afecta a todas las filas de la tabla.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Update only Alice's address
sql = "UPDATE customers SET address = %s WHERE name = %s"
val = ("New Street 10", "Alice")
mycursor.execute(sql, val)
mydb.commit()
print(mycursor.rowcount, "row(s) updated")
except Error as e:
print(f"Error: {e}")
mydb.rollback()
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Salida de ejemplo:
1 row(s) updatedSiempre verifica tu condición WHERE con un SELECT primero antes de ejecutar un UPDATE o DELETE. Una condición incorrecta o ausente en una tabla de producción puede ser difícil de revertir. Consulta MySQL Update y MySQL Delete para más detalles.
Obtener una fila vs todas las filas
Tras execute(), elige cuántas filas recuperar:
| Método | Devuelve | Úsalo cuando |
|---|---|---|
fetchone() | Primera fila coincidente (o None) | Esperas como máximo un resultado, p. ej. búsqueda por clave primaria |
fetchmany(n) | Hasta n filas | Paginación o previsualizaciones limitadas |
fetchall() | Todas las filas coincidentes como una lista | Conjuntos de resultados pequeños donde cargar todas las filas a la vez es viable |
mycursor.execute("SELECT * FROM customers WHERE age > %s", (25,))
# Fetch only the first result
first = mycursor.fetchone()
print(first) # (1, 'Alice', 'Oak Avenue 1', 30)Para conjuntos de resultados grandes, prefiere fetchmany() en un bucle o usa un cursor del lado del servidor (MySQLCursorBuffered) para evitar cargar todas las filas en memoria de una vez.
Errores comunes que debes evitar
Usar = para comprobar NULL. WHERE address = NULL nunca devuelve ninguna fila; siempre usa IS NULL.
Olvidar la coma final en una tupla de un solo valor. Escribir val = ("Alice") crea un string, no una tupla. Escribe val = ("Alice",).
Formatear valores como strings en el SQL. Los f-strings y el formato con % omiten la parametrización. Pasa los valores como segundo argumento a execute().
Omitir WHERE en UPDATE o DELETE. Sin una cláusula WHERE, se ven afectadas todas las filas de la tabla.
Usar Python None donde se necesita SQL NULL. mysql-connector-python mapea automáticamente Python None a SQL NULL, por lo que mycursor.execute("UPDATE customers SET address = %s WHERE id = %s", (None, 1)) establece address como NULL correctamente.
Qué hacer a continuación
- MySQL Order By — ordena las filas que devuelve tu cláusula
WHERE. - MySQL Limit — limita el número de filas devueltas.
- MySQL Update — modifica las filas que cumplen una condición.
- MySQL Delete — elimina las filas que cumplen una condición.
- MySQL Join — filtra en múltiples tablas con
WHEREcombinado con joins.