Модуль 2. Основы баз данных и SQLite
1. Цели модуля
- Понять, что такое база данных и зачем она нужна.
- Разобраться в понятиях таблицы, записи, поля и ключа.
- Познакомиться с SQLite как с простой учебной СУБД.
- Освоить базовые SQL-команды.
- Научиться работать с базой через
SQLiteStudio.
2. Что такое база данных
2.1 Теория
База данных и её назначение
База данных — это место, где программа хранит данные в удобном и упорядоченном виде. Проще всего представить её как "умную таблицу", в которой можно быстро найти нужную информацию, изменить её или добавить новую.
Например, если хранить список студентов в обычном .txt файле, то очень быстро начнётся путаница: где чей возраст, как найти одного студента, как добавить нового, как не испортить старые данные. База данных нужна как раз для того, чтобы такого хаоса не было.
Основные понятия
- таблица — набор однотипных данных;
- запись — одна строка таблицы;
- поле — отдельный столбец;
- первичный ключ — поле, которое уникально определяет запись.
Например, в таблице students могут быть поля id, name, age, group_name.
Как это выглядит в реальности
Для начала удобно представлять базу данных как файл, внутри которого лежат таблицы. В каждой таблице есть:
- структура — какие столбцы существуют и какого они типа;
- данные — какие конкретно записи уже сохранены.
Например, если таблица students имеет поля id, name, age, group_name, то структура отвечает на вопрос "что тут вообще можно хранить", а данные отвечают на вопрос "что уже лежит в таблице прямо сейчас".
Типы данных в SQLite
В учебных примерах чаще всего встречаются такие типы:
INTEGER— целые числа;TEXT— текст;REAL— дробные числа;NULL— пустое значение.
Проще говоря, тип поля подсказывает базе данных, что именно здесь должно лежать. Если поле age задумано как возраст, то логично хранить там число, а не текст "девятнадцать".
Ограничения полей
Кроме типа, у поля могут быть ограничения:
PRIMARY KEY— значение должно быть уникальным;AUTOINCREMENT— значение будет увеличиваться автоматически;NOT NULL— поле нельзя оставлять пустым;UNIQUE— значения не должны повторяться.
Проще говоря, ограничения нужны для порядка. Они не дают случайно записать в таблицу что-то неправильное или пустое там, где это недопустимо.
Например, запись без имени в таблице студентов обычно не имеет смысла, поэтому для name часто ставят NOT NULL.
Почему именно SQLite
SQLite подходит для разных задач, потому что:
- не требует отдельного сервера;
- хранит базу в одном файле;
- проста в установке и использовании;
- хорошо подходит для небольших проектов;
- легко открывается как в Python, так и в сторонних программах.
Что такое SQLiteStudio
SQLiteStudio — это графическая программа для работы с SQLite. В ней удобно:
- создавать базу данных;
- создавать таблицы;
- добавлять и редактировать записи;
- запускать SQL-запросы;
- визуально смотреть структуру базы.
Это хороший первый шаг перед тем, как подключать базу к Python-коду. Сначала обучающиеся видят базу визуально, создают таблицу и записи вручную, а уже потом работают с ней программно.
Частые ошибки
- Путать базу данных и таблицу.
- Считать, что запись и поле — это одно и то же.
- Не понимать, зачем нужен
id. - Учить термины отдельно от примеров.
2.2 Практика
Задание 1. Разбираем таблицу
Цель - понять структуру таблицы.
Шаги:
- Представьте таблицу
students. - Определите поля
id,name,age,group_name. - Объясните, что будет храниться в одной записи.
- Отдельно разберите, зачем нужен
id.
Задание 2. Первое знакомство с SQLiteStudio
Цель - увидеть базу данных через интерфейс программы.
Шаги:
- Откройте
SQLiteStudio. - Создайте новую базу данных.
- Посмотрите, как отображаются таблицы и поля.
- Найдите окно для выполнения SQL-запросов.
3. Базовые SQL-команды
3.1 Теория
Что такое SQL
SQL — это язык запросов для работы с базами данных. С его помощью можно создавать таблицы, добавлять записи, искать данные, изменять их и удалять.
Если совсем просто, SQL — это набор команд, которыми мы "говорим" базе данных, что нужно сделать.
В этой теме важно не просто выучить команды, а понять, какую задачу решает каждая из них.
Полезно дать такую опору:
CREATE— создаём структуру;INSERT— добавляем новые данные;SELECT— читаем данные;UPDATE— меняем данные;DELETE— удаляем данные.
То есть часть команд работает со структурой таблицы, а часть — с её содержимым.
CREATE TABLE
Создаёт таблицу.
sql
CREATE TABLE students (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER,
group_name TEXT
);Разберём по-человечески:
CREATE TABLE students— команда "создай таблицу с именемstudents".- Круглые скобки
()содержат описание столбцов таблицы. id INTEGER PRIMARY KEY AUTOINCREMENT— столбецid, в котором будет число, причём уникальное и увеличивающееся автоматически.name TEXT NOT NULL— столбецname, в котором хранится текст, и он не может быть пустым.age INTEGER— столбец для возраста.group_name TEXT— столбец для названия группы.;в конце означает, что команда закончилась.
Иначе говоря, этот запрос не добавляет студентов. Он только создаёт "пустую коробку", в которую потом можно будет складывать записи.
INSERT
Добавляет запись в таблицу.
sql
INSERT INTO students (name, age, group_name)
VALUES ('Анна', 19, 'Вп41');Разберём по строкам:
INSERT INTO students— команда "добавь новую запись в таблицуstudents".(name, age, group_name)— перечисляем, в какие именно столбцы будем записывать значения.VALUES ('Анна', 19, 'Вп41')— перечисляем сами значения в том же порядке.'Анна'попадёт вname.19попадёт вage.'Вп41'попадёт вgroup_name.
В этом запросе мы не указываем id, потому что SQLite создаст его сама.
SELECT
Читает данные из таблицы.
sql
SELECT * FROM students;Символ * означает "все столбцы". Полезно сразу показать и более точный вариант:
sql
SELECT name, age FROM students;Разберём первый вариант:
SELECT— команда "покажи данные".*— показать все столбцы.FROM students— брать данные из таблицыstudents.
То есть запрос SELECT * FROM students; означает: "Покажи мне все данные из таблицы students".
Разберём второй вариант:
SELECT name, age— показать только столбцыnameиage.FROM students— брать их из таблицыstudents.
Такой запрос вернёт не всю строку целиком, а только нужные поля.
WHERE
Фильтрует записи по условию.
sql
SELECT * FROM students
WHERE age >= 18;Условие WHERE отвечает за фильтрацию. Без него запрос читает или изменяет все записи таблицы. Именно поэтому WHERE особенно важен в UPDATE и DELETE.
Разберём этот запрос:
SELECT *— показать все столбцы.FROM students— из таблицыstudents.WHERE age >= 18— но только те строки, где возраст больше или равен 18.
То есть база сначала смотрит на все записи, а потом оставляет только подходящие.
Примеры условий:
sql
SELECT * FROM students WHERE age = 19;
SELECT * FROM students WHERE group_name = 'Вп41';
SELECT * FROM students WHERE age > 18;UPDATE
Изменяет существующие записи.
sql
UPDATE students
SET age = 20
WHERE name = 'Анна';Разберём по шагам:
UPDATE students— команда "измени данные в таблицеstudents".SET age = 20— в подходящих строках поставь возраст20.WHERE name = 'Анна'— менять только там, где имя равноАнна.
Этот запрос не создаёт новую запись, а изменяет уже существующую.
DELETE
Удаляет записи.
sql
DELETE FROM students
WHERE name = 'Анна';Разберём по шагам:
DELETE FROM students— команда "удали записи из таблицыstudents".WHERE name = 'Анна'— удалить только те записи, где имя равноАнна.
Этот запрос удаляет строки, которые подходят под условие. Если забыть WHERE, будут удалены все записи таблицы.
Как читать SQL-запрос как алгоритм
Часто проще не заучивать синтаксис, а переводить запрос на обычный язык.
Например:
sql
SELECT name, age FROM students
WHERE age >= 18;Можно прочитать так:
- Возьми таблицу
students. - Найди в ней записи, где
age >= 18. - Покажи только столбцы
nameиage.
Такой подход снижает ощущение, что SQL — это набор непонятных команд.
Частые ошибки
- Писать запрос с ошибкой в названии поля или таблицы.
- Забывать
WHEREвUPDATEилиDELETE. - Не понимать, какие данные уже есть в таблице перед изменением.
- Путать создание таблицы и добавление записи в неё.
3.2 Практика
Задание 1. Таблица книг
Цель - создать таблицу и выполнить основные SQL-команды.
Шаги:
- В
SQLiteStudioсоздайте базуlibrary.db. - Создайте таблицу
booksс полямиid,title,author,year. - Добавьте 2-3 книги через
INSERT. - Выполните
SELECT * FROM books. - Измените одну запись через
UPDATE. - Удалите одну запись через
DELETE. - Отдельно объясните словами, что делает каждый запрос.
Пример SQL:
sql
CREATE TABLE books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
year INTEGER
);
INSERT INTO books (title, author, year)
VALUES ('1984', 'Оруэлл', 1949);
SELECT * FROM books;Разбор:
CREATE TABLE books— создаём таблицуbooks.id INTEGER PRIMARY KEY AUTOINCREMENT— служебный номер книги, который SQLite будет назначать сама.title TEXT NOT NULL— название книги, пустым быть не может.author TEXT NOT NULL— автор книги, тоже не может быть пустым.year INTEGER— год издания.INSERT INTO books ...— добавляем новую книгу в таблицу.VALUES ('1984', 'Оруэлл', 1949)— записываем конкретные данные о книге.SELECT * FROM books;— просим базу показать все книги, которые сейчас есть в таблице.
Задание 2. Мини-база задач
Цель - закрепить работу с таблицей через интерфейс SQLiteStudio.
Шаги:
- Создайте базу
tasks.db. - Создайте таблицу
tasksс полямиid,title,status. - Добавьте несколько записей вручную.
- Выполните
SELECT * FROM tasks;. - Измените статус одной задачи.
- Объясните, какие поля относятся к структуре таблицы, а какие значения относятся к данным.
Как объяснять любой SQL-запрос
Если разбирать запрос пока сложно, удобно использовать один и тот же шаблон:
- Что делает команда: создаёт, добавляет, показывает, изменяет или удаляет.
- С какой таблицей она работает.
- Какие столбцы участвуют.
- Есть ли условие
WHERE. - Что изменится в базе после выполнения команды.
4. Работа с SQLite из Python
4.1 Теория
Как подключиться к базе данных
В Python уже есть встроенный модуль sqlite3 для работы с SQLite. Его не нужно устанавливать отдельно: достаточно import sqlite3.
Базовая цепочка действий:
- Подключились к базе.
- Создали курсор.
- Выполнили SQL-команду.
- Сохранили изменения.
- Закрыли соединение.
Короткая формула: подключение -> выполнение -> сохранение -> закрытие.
Вот базовый код:
python
import sqlite3
# 1. Подключаемся к базе данных (если файла нет, SQLite создаст его)
conn = sqlite3.connect('school.db')
# 2. Создаём курсор
cursor = conn.cursor()
# 3. Выполняем SQL-запрос (например, создаём таблицу)
cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
age INTEGER
)
""")
# 4. Сохраняем изменения
conn.commit()
# 5. Закрываем соединение
conn.close()Разбор по шагам:
import sqlite3: импортируем модуль.sqlite3.connect('school.db'): эта команда создаёт соединение с файломschool.db. Если такого файла нет, он будет создан. Переменнаяconn— это и есть наше подключение.conn.cursor(): создаёт объектcursor. Через него мы будем отправлять команды в базу данных.cursor.execute(...): выполняет SQL-запрос, который передан в виде строки. Здесь мы создаём таблицуstudents, если она ещё не существует (IF NOT EXISTS).conn.commit(): подтверждает все изменения, сделанные с момента последнегоcommit. Без этой команды ничего не сохранится в файле базы данных.conn.close(): закрывает соединение. Это важный шаг, который освобождает файл базы данных.
Очень важная подсказка для новичка
SELECTтолько читает данные. После негоcommit()обычно не нужен.INSERT,UPDATE,DELETE,CREATE TABLEменяют базу. После них нуженcommit().- Если забыть
close(), файл базы может остаться занятым.
Мини-пример: добавить студента и прочитать таблицу
python
import sqlite3
conn = sqlite3.connect('school.db')
cursor = conn.cursor()
cursor.execute(
"INSERT INTO students (name, age) VALUES (?, ?)",
('Анна', 19)
)
conn.commit()
cursor.execute("SELECT id, name, age FROM students")
rows = cursor.fetchall()
for row in rows:
print(row)
conn.close()Разбор этого примера:
- Открыли подключение.
- Добавили запись через
INSERT. - Сохранили изменение (
commit). - Выполнили
SELECTи получили все строки (fetchall). - Вывели результат.
- Закрыли подключение.
Почему лучше писать VALUES (?, ?):
- Это безопаснее.
- Меньше ошибок с кавычками.
- Это правильная практика для параметров в SQL.
Контекстный менеджер with
Чтобы не забывать вызывать conn.commit() и conn.close(), можно использовать конструкцию with. Она делает код чище и безопаснее:
python
import sqlite3
db_name = 'school.db'
with sqlite3.connect(db_name) as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM students")
# Получаем результат запроса
all_students = cursor.fetchall()
print(all_students)В этом примере:
with sqlite3.connect(db_name) as conn:— соединение будет автоматически закрыто после выхода из блокаwith.- Если внутри блока
withне возникнет ошибок, изменения будут автоматически сохранены (commit). Если произойдёт ошибка, изменения будут отменены (rollback). cursor.fetchall(): получает все строки, которые вернулSELECT-запрос.
Этот способ является предпочтительным, так как он помогает избежать многих распространённых ошибок.
Частые ошибки и как их избежать
- Ошибка: забыли
commit()после изменения данных. Результат: программа отработала, но в базе ничего не поменялось. - Ошибка: закрыли соединение слишком рано. Результат: следующие запросы падают с ошибкой.
- Ошибка: подставляют значения в SQL через f-строки. Результат: небезопасный и хрупкий код. Правильно: передавать параметры отдельно, через
?. - Ошибка: думают, что курсор работает сам по себе. Важно:
cursorсуществует только внутри активного соединенияconn.
Шаблон, который можно использовать почти всегда
import sqlite3with sqlite3.connect('имя_базы.db') as conn:cursor = conn.cursor()cursor.execute("SQL", параметры)- Если это
SELECT:fetchone()илиfetchall() - Если это изменение:
commit()(или положиться наwith)
4.2 Практика
Задание 1. Первое подключение к базе
Цель - открыть файл базы данных из Python и проверить, что подключение работает.
Шаги:
- Создайте файл
lesson4_task1.py. - Подключитесь к базе
school.dbчерезsqlite3.connect(...). - Создайте курсор.
- Выполните запрос
SELECT 1;. - Выведите результат на экран.
- Закройте соединение.
Ожидаемый результат: программа запускается без ошибок и выводит значение 1.
Задание 2. Чтение данных из таблицы
Цель - получить и вывести записи из таблицы students.
Шаги:
- Подключитесь к
school.db. - Выполните
SELECT id, name, age FROM students;. - Получите все строки через
fetchall(). - Выведите каждую запись в цикле
for. - Отдельно посчитайте, сколько строк вернулось.
Ожидаемый результат: на экран выводится список студентов и количество найденных записей.
Задание 3. Добавление и изменение записи
Цель - отработать INSERT, UPDATE и commit() из Python-кода.
Шаги:
- Добавьте в таблицу нового студента через параметризованный запрос с
?. - Сохраните изменения через
commit(). - Измените возраст этого студента через
UPDATE ... WHERE .... - Снова выполните
commit(). - Выполните
SELECTи убедитесь, что данные действительно изменились.
Ожидаемый результат: в таблице есть новая запись, и у неё обновлён возраст.
Задание 4. Мини-CRUD на Python
Цель - связать все основные действия с базой в одном скрипте.
Шаги:
- Создайте скрипт
lesson4_task4.py. - Реализуйте функцию
add_student(name, age). - Реализуйте функцию
show_students(). - Реализуйте функцию
update_student_age(student_id, new_age). - Реализуйте функцию
delete_student(student_id). - Внизу файла вызовите функции в таком порядке: добавить -> показать -> изменить -> показать -> удалить -> показать.
- Проверьте, что после каждого шага результат соответствует ожидаемому.
Ожидаемый результат: скрипт демонстрирует полный цикл работы с базой (Create, Read, Update, Delete).