Урок 80. MySQL и Python

📁 Блок: Базы данных ⏱️ Время изучения: ~90 мин 🎯 Сложность: Средняя
#close #for #in

⚡ Кратко: решения

К каждому заданию приведён рабочий код. Обращай внимание на:

  • запятую в кортеже из одного значения (value,);
  • connection.commit() для изменяющих данных запросов;
  • параметризованные запросы вместо f-string;
  • with и обработку исключений в финальных решениях.

✅ Решения заданий

Задание 1. Подключение и список отделов

Файл: task01_departments.py

import pymysql

config = {
    "host": "localhost",
    "user": "root",
    "password": "yourpassword",
    "database": "hr",
    "charset": "utf8mb4",
}

connection = pymysql.connect(**config)
cursor = connection.cursor()

cursor.execute("SELECT department_id, department_name FROM departments")
for department_id, department_name in cursor:
    print(f"{department_id}: {department_name}")

cursor.close()
connection.close()

Пояснение: создаём соединение и курсор, выполняем SELECT, итерируемся по строкам и печатаем результат. В конце закрываем курсор и соединение.

Задание 2. Параметризованный SELECT

Файл: task02_param_select.py

import pymysql

config = {
    "host": "localhost",
    "user": "root",
    "password": "yourpassword",
    "database": "hr",
    "charset": "utf8mb4",
}

department_id = 50

connection = pymysql.connect(**config)
try:
    cursor = connection.cursor()
    cursor.execute(
        "SELECT first_name, last_name FROM employees WHERE department_id = %s",
        (department_id,)
    )
    for first_name, last_name in cursor:
        print(f"{first_name} {last_name}")
finally:
    cursor.close()
    connection.close()

Пояснение: значение department_id передаётся вторым аргументом в виде кортежа. Плейсхолдер %s заменяется безопасно.

Задание 3. Добавление нового отдела

Файл: task03_insert.py

import pymysql

config = {
    "host": "localhost",
    "user": "root",
    "password": "yourpassword",
    "database": "hr",
    "charset": "utf8mb4",
}

connection = pymysql.connect(**config)
try:
    cursor = connection.cursor()
    cursor.execute(
        "INSERT INTO departments (department_name, location_id) VALUES (%s, %s)",
        ("Data Science", 1700)
    )
    connection.commit()
    print("Добавлено строк:", cursor.rowcount)
finally:
    cursor.close()
    connection.close()

Пояснение: для сохранения изменений в базе обязателен connection.commit(). cursor.rowcount показывает, сколько строк было затронуто.

Задание 4. Безопасный запрос по вводу пользователя

Файл: task04_safe_input.py

import pymysql

config = {
    "host": "localhost",
    "user": "root",
    "password": "yourpassword",
    "database": "hr",
    "charset": "utf8mb4",
}

user_input = input("Введите department_id: ")

connection = pymysql.connect(**config)
try:
    cursor = connection.cursor()
    cursor.execute(
        "SELECT department_name FROM departments WHERE department_id = %s",
        (user_input,)
    )
    row = cursor.fetchone()
    if row:
        print("Название отдела:", row[0])
    else:
        print("Отдел не найден")
finally:
    cursor.close()
    connection.close()

Пояснение: даже если пользователь введёт 1 OR 1=1, библиотека воспримет это как одно строковое значение. SQL-инъекция невозможна.

Задание 5. Рефакторинг на with и обработку ошибок

Файл: task05_with_errors.py

import pymysql

config = {
    "host": "localhost",
    "user": "root",
    "password": "yourpassword",
    "database": "hr",
    "charset": "utf8mb4",
}

try:
    with pymysql.connect(**config) as connection:
        with connection.cursor() as cursor:
            cursor.execute("SELECT department_id, department_name FROM departments")
            for department_id, department_name in cursor:
                print(f"{department_id}: {department_name}")
except pymysql.MySQLError as e:
    print("Ошибка при работе с базой данных:", e)

Пояснение: with закрывает соединение и курсор автоматически, а except перехватывает ошибки MySQL, чтобы программа не падала.

Задание 6. Подготовка к домашнему заданию: список стран

Файл: task06_countries.py

import pymysql

config = {
    "host": "localhost",
    "user": "root",
    "password": "yourpassword",
    "database": "world",
    "charset": "utf8mb4",
}

with pymysql.connect(**config) as connection:
    with connection.cursor() as cursor:
        cursor.execute("SELECT name FROM country ORDER BY name")
        for index, row in enumerate(cursor, start=1):
            print(f"{index}. {row[0]}")

Пояснение: используем enumerate(cursor, start=1), чтобы автоматически пронумеровать строки. Запрос упорядочен по имени страны.