MySQL Where
Узнайте, как использовать WHERE в MySQL из Python с параметризованными запросами, операторами сравнения, LIKE, IN, BETWEEN, проверками NULL и составными условиями.
Конструкция WHERE — основной способ фильтрации строк в операторах MySQL SELECT, UPDATE и DELETE. В этой главе показано, как использовать её из Python с помощью mysql-connector-python: фильтры по одному условию, операторы сравнения, LIKE, IN, BETWEEN, проверки NULL и составная логика AND/OR — всё с параметризованными запросами для защиты от SQL-инъекций.
Предварительные требования
Убедитесь, что перед запуском примеров у вас есть следующее:
- Python 3.x и работающий сервер MySQL.
- Установленный
mysql-connector-python:
pip install mysql-connector-python- База данных с уже созданной таблицей
customers— смотрите MySQL Create Database и MySQL Create Table, если вы ещё не выполнили эту настройку.
В примерах используется следующая таблица с несколькими строками:
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);Зачем использовать параметризованные запросы
Прежде чем перейти к примерам кода, запомните одно правило: никогда не формируйте условие WHERE путём конкатенации строк, введённых пользователем, непосредственно в SQL. Этот подход опасен:
# NEVER do this — SQL injection risk
name = input("Enter name: ")
sql = "SELECT * FROM customers WHERE name = '" + name + "'"Если пользователь введёт ' OR '1'='1, запрос вернёт все строки. Вместо этого всегда передавайте значения через параметризованный интерфейс mysql-connector-python:
sql = "SELECT * FROM customers WHERE name = %s"
mycursor.execute(sql, (name,))Коннектор безопасно экранирует значение до того, как оно попадёт в базу данных. Заполнитель всегда %s, независимо от типа данных столбца (целое число, string, дата и т. д.).
Фильтрация по точному значению
Наиболее распространённый случай: получить строки, в которых столбец равен определённому значению.
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()Пример вывода:
(1, 'Alice', 'Oak Avenue 1', 30)Обратите внимание, что val должен быть кортежем, даже если в нём только одно значение — отсюда замыкающая запятая в ("Alice",).
Операторы сравнения
Конструкция WHERE поддерживает все стандартные операторы сравнения SQL:
| Оператор | Значение | Пример условия |
|---|---|---|
= | Равно | age = 30 |
<> или != | Не равно | age <> 30 |
> | Больше | age > 25 |
>= | Больше или равно | age >= 28 |
< | Меньше | age < 30 |
<= | Меньше или равно | age <= 30 |
Пример: строки, где возраст больше 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()Пример вывода:
('Alice', 30)
('Charlie', 35)Сопоставление по шаблону с LIKE
LIKE сопоставляет шаблоны в строковых столбцах. Доступны два символа-подстановочных знака:
%— соответствует нулю или более символам._— соответствует ровно одному символу.
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()Пример вывода:
('Alice', 'Oak Avenue 1')
('Diana', 'Oak Avenue 3')LIKE нечувствителен к регистру для столбцов с кодировкой utf8mb4 по умолчанию. Используйте LIKE BINARY, если требуется сопоставление с учётом регистра.
Проверка нескольких значений с IN
IN проверяет, входит ли значение столбца в список. Это эквивалентно цепочке нескольких условий 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()
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()Пример вывода:
('Alice', 30)
('Charlie', 35)
('Eve', 22)Поскольку количество значений в IN может меняться во время выполнения, приведённый выше шаблон динамически формирует строку заполнителей (", ".join(["%s"] * len(names))). Это сохраняет параметризацию независимо от длины списка.
Фильтрация диапазона с BETWEEN
BETWEEN выбирает строки, у которых значение столбца попадает в включительный диапазон:
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()Пример вывода:
('Alice', 30)
('Bob', 25)
('Diana', 28)BETWEEN 25 AND 30 включает оба граничных значения (25 и 30). Работает с датами и строками, а также с числами.
Проверка значений NULL
Значение NULL означает, что в поле нет данных. Проверить NULL с помощью = невозможно — необходимо использовать IS NULL или 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()Пример вывода:
('Eve',)IS NULL и IS NOT NULL не принимают параметров, поэтому второй аргумент в execute() не передаётся.
Составные условия с AND и OR
Объединяйте несколько условий в одном предложении WHERE с помощью AND (все условия должны выполняться) и OR (хотя бы одно условие должно выполняться).
Пример 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()Пример вывода:
('Alice', 'Oak Avenue 1', 30)Диана живёт на Oak Avenue, но ей 28 лет, поэтому она не удовлетворяет условию age > 28.
Пример 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()Пример вывода:
('Alice', 30)
('Eve', 22)Используйте скобки для управления приоритетом при смешивании AND и OR: (a OR b) AND c ведёт себя иначе, чем a OR (b AND c).
Использование WHERE с UPDATE и DELETE
Конструкция WHERE одинаково важна в операторах UPDATE и DELETE. Без неё оператор затронет каждую строку таблицы.
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()Пример вывода:
1 row(s) updatedВсегда проверяйте условие WHERE с помощью SELECT перед выполнением UPDATE или DELETE. Пропущенное или неверное условие в производственной таблице может быть трудно обратить. Подробнее см. MySQL Update и MySQL Delete.
Получение одной строки или всех строк
После execute() выберите, сколько строк нужно получить:
| Метод | Возвращает | Использовать когда |
|---|---|---|
fetchone() | Первую подходящую строку (или None) | Ожидается не более одного результата, например поиск по первичному ключу |
fetchmany(n) | До n строк | Постраничный вывод или ограниченный предварительный просмотр |
fetchall() | Все подходящие строки в виде списка | Небольшие наборы результатов, где загрузка всех строк за раз допустима |
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)Для больших наборов результатов предпочтительнее использовать fetchmany() в цикле или серверный курсор (MySQLCursorBuffered), чтобы не загружать все строки в память сразу.
Распространённые ошибки
Использование = для проверки NULL. WHERE address = NULL никогда не вернёт строк; всегда используйте IS NULL.
Забытая замыкающая запятая в кортеже с одним значением. val = ("Alice") создаёт string, а не кортеж. Пишите val = ("Alice",).
Форматирование значений в SQL в виде строк. F-строки и форматирование через % обходят параметризацию. Передавайте значения вторым аргументом в execute().
Пропуск WHERE в UPDATE или DELETE. Без конструкции WHERE будет затронута каждая строка таблицы.
Использование Python None там, где SQL ожидает NULL. mysql-connector-python автоматически преобразует Python None в SQL NULL, поэтому mycursor.execute("UPDATE customers SET address = %s WHERE id = %s", (None, 1)) корректно устанавливает address в NULL.
Что делать дальше
- MySQL Order By — сортировка строк, возвращённых конструкцией
WHERE. - MySQL Limit — ограничение количества возвращаемых строк.
- MySQL Update — изменение строк, соответствующих условию.
- MySQL Delete — удаление строк, соответствующих условию.
- MySQL Join — фильтрация по нескольким таблицам с помощью
WHEREв сочетании с объединениями.