MySQL SELECT в Python
Как использовать SELECT в Python с mysql-connector-python: получение всех строк, одной строки, отдельных столбцов, fetchone и fetchall.
Оператор SELECT лежит в основе любой операции чтения из базы данных. В Python он выполняется через объект cursor, предоставляемый библиотекой mysql-connector-python, а результаты извлекаются с помощью fetchall(), fetchone() или fetchmany(). В этой главе рассматриваются все три метода получения данных, выборка конкретных столбцов, работа с именами столбцов и паттерны обработки ошибок, необходимые в production-коде.
Предварительные требования
Установите MySQL-коннектор, если ещё не сделали этого:
pip install mysql-connector-pythonВо всех примерах предполагается:
- Работающий MySQL-сервер (локальный или удалённый).
- База данных
mydatabaseс таблицейcustomers, содержащей как минимум столбцыid,nameиaddress.
Следуйте инструкциям из Python MySQL Create Table, чтобы создать таблицу, и Python MySQL Insert, чтобы заполнить её тестовыми данными перед запуском примеров SELECT ниже.
Подключение к базе данных
Каждый пример начинается с объекта подключения. Чтобы не повторять настройку в каждом фрагменте кода, разместите её в одном месте и используйте повторно:
import mysql.connector
from mysql.connector import Error
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)Замените yourusername и yourpassword на ваши реальные учётные данные. Смотрите Python MySQL Get Started, чтобы узнать, как хранить учётные данные в переменных окружения вместо жёсткого кодирования.
Выборка всех строк с fetchall()
fetchall() извлекает все строки, возвращённые запросом, и сохраняет их в виде Python-списка кортежей. Используйте его, когда результирующий набор достаточно мал, чтобы без труда поместиться в памяти.
Выборка всех записей из таблицы 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()Каждая row — это кортеж, значения которого соответствуют столбцам таблицы в том порядке, в котором они указаны в операторе CREATE TABLE. Для таблицы customers со столбцами (id, name, address) вывод будет примерно следующим:
(1, 'John', '123 Main St')
(2, 'Susan', '456 Oak Ave')
(3, 'Maria', '789 Pine Rd')Зачем оборачивать всё в try/except/finally?
Если между открытием и закрытием соединения возникает исключение, соединение «утекает» — оно остаётся открытым и потребляет ресурсы сервера до тех пор, пока сервер не закроет его по таймауту. Блок finally гарантирует, что cursor.close() и connection.close() будут вызваны всегда, даже если что-то пошло не так.
Выборка одной строки с fetchone()
Когда нужна только первая подходящая строка — или вы знаете, что запрос возвращает ровно один результат — fetchone() эффективнее, чем fetchall(). Метод возвращает один кортеж или None, если результатов нет.
Получение одной строки из таблицы 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() перемещает внутренний указатель курсора вперёд. При повторном вызове возвращается следующая строка. Это делает метод удобным для последовательного перебора результатов по одной строке без загрузки всего результирующего набора в память.
Выборка конкретных столбцов
SELECT * возвращает все столбцы таблицы. Для больших таблиц или когда нужны лишь несколько полей, укажите столбцы явно. Это уменьшает объём данных, передаваемых по сети, и делает намерение кода очевидным.
Выборка только столбцов name и 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()Вывод (пример):
('John', '123 Main St')
('Susan', '456 Oak Ave')
('Maria', '789 Pine Rd')Получение строк пакетами с fetchmany()
fetchmany(size) извлекает size строк за раз. Используйте его, когда результирующий набор слишком велик для fetchall(), но вы всё равно хотите обрабатывать строки пакетами, а не по одной.
Обработка результатов по 10 строк за раз
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() возвращает пустой список, когда строк больше нет — это именно то, что проверяет условие if not rows: break.
Доступ к столбцам по имени с помощью словарного курсора
По умолчанию каждая строка — это обычный кортеж. При большом количестве столбцов обращение через row[4] вместо row["email"] делает код труднее для чтения и тихо ломается при изменении порядка столбцов. Передайте dictionary=True в конструктор курсора, чтобы получать каждую строку в виде dict.
Использование словарного курсора для доступа к столбцам по имени
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()Вывод:
ID: 1, Name: John, Address: 123 Main St
ID: 2, Name: Susan, Address: 456 Oak AveСловарные курсоры делают код самодокументируемым и устойчивым к изменению порядка столбцов.
Фильтрация строк с WHERE
Чтобы получить только строки, удовлетворяющие условию, добавьте предложение WHERE. Всегда используйте параметризованные запросы — никогда не подставляйте значения, введённые пользователем, непосредственно в SQL-строку, так как это открывает дверь для SQL-инъекций.
Получение клиентов, проживающих на определённой улице
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()Заполнитель %s подставляется драйвером коннектора, который безопасно экранирует значение. Смотрите Python MySQL Where для подробного описания фильтрации, включая несколько условий с AND/OR.
Использование SELECT с ORDER BY и LIMIT
Сочетайте SELECT с ORDER BY для сортировки результатов и LIMIT для ограничения количества возвращаемых строк. Этот паттерн незаменим для отображения последних записей или реализации пагинации.
Получение 3 клиентов с наибольшими ID, отсортированных от новых к старым
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()Для отдельного руководства по сортировке смотрите Python MySQL Order By. По пагинации с OFFSET — Python MySQL Limit.
Получение имён столбцов через cursor.description
После вызова execute() атрибут description курсора содержит метаданные о каждом столбце результата — включая его имя. Это полезно, когда имена столбцов нужны динамически (например, при формировании CSV-экспорта) без их жёсткого кодирования.
Вывод имён столбцов вместе с данными
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()Вывод (пример):
Columns: ['id', 'name', 'address']
{'id': 1, 'name': 'John', 'address': '123 Main St'}
{'id': 2, 'name': 'Susan', 'address': '456 Oak Ave'}Выбор между fetchall(), fetchone() и fetchmany()
| Метод | Возвращает | Лучше всего для |
|---|---|---|
fetchall() | Список всех кортежей | Небольшие и средние результирующие наборы, когда все строки нужны сразу |
fetchone() | Один кортеж или None | Поиск по первичному ключу; последовательный перебор строк |
fetchmany(n) | Список до n кортежей | Большие результирующие наборы, обрабатываемые потоковыми пакетами |
Если вызвать fetchall() для набора из миллиона строк, Python одновременно сохранит все миллион кортежей в памяти. Для больших таблиц используйте fetchmany() или добавьте предложение LIMIT к запросу.
Распространённые ошибки и способы их исправления
| Ошибка | Вероятная причина | Решение |
|---|---|---|
mysql.connector.errors.ProgrammingError: Table doesn't exist | Неверное имя таблицы или не выбрана база данных | Проверьте имя таблицы; убедитесь, что параметр database задан в connect() |
mysql.connector.errors.InterfaceError: No result set | Вызов fetchall() после не-SELECT оператора | Вызывайте методы fetch только после SELECT, SHOW или других операторов, возвращающих результат |
mysql.connector.errors.DatabaseError: Lost connection | Таймаут сети или перезапуск сервера | Переустановите соединение; для долгоживущих приложений используйте пул соединений |
InternalError: Unread result found | Начало нового execute() до получения предыдущих результатов | Вызовите fetchall() или cursor.reset(), чтобы очистить предыдущий результирующий набор |
Резюме
- Выполняйте оператор
SELECTс помощьюcursor.execute("SELECT ..."). - Используйте
fetchall()для небольших результирующих наборов,fetchone()для одной строки иfetchmany(n)для больших наборов данных, обрабатываемых пакетами. - Передавайте
dictionary=Trueкурсору, чтобы обращаться к столбцам по имени вместо индекса. - Всегда используйте параметризованные заполнители
%sпри фильтрации с пользовательскими значениями. - Оборачивайте каждую операцию с базой данных в
try/except/finally, чтобы гарантировать закрытие соединения при возникновении ошибки.
Связанные главы
- Python MySQL Get Started — установка драйвера и установка соединения
- Python MySQL Create Table — определение схемы таблицы для ваших запросов
- Python MySQL Insert — добавление строк перед их запросом
- Python MySQL Where — фильтрация результатов SELECT по условиям
- Python MySQL Order By — сортировка результатов SELECT
- Python MySQL Limit — ограничение количества возвращаемых строк
- Python MySQL Join — объединение данных из нескольких таблиц