Перейти к содержанию

172 уроков, 13 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 1 из 10 Начальный 35 мин 100 XP

SQL с нуля через Python: первая база SQLite и таблица

Первая настоящая база данных без установки серверов: import sqlite3, курсор, CREATE TABLE и первые строки — всё исполняется прямо на странице.

Редакция Питоники

Ты уже умеешь хранить данные в списках и словарях, но закрыл программу — и всё исчезло. Записал в файл — а найти «все книги дороже пятисот» уже требует ручного перебора. Именно эту скуку убирают базы данных, а язык, на котором с ними разговаривают, называется SQL. Хороший новостной фон: он не менялся по сути лет тридцать и выучен один раз — работает везде, от мобильных приложений до аналитических отделов.

У этого раздела есть суперспособность: SQLite входит в стандартную библиотеку Python, поэтому каждая таблица в код-блоках ниже — настоящая. Жмёшь «Запустить» — в браузере поднимается живая база, создаётся таблица, вставляются строки, и SELECT возвращает данные. Никаких имитаций и никаких установок.

Что такое база данных и SQL на пальцах?

База данных — это умный файл: движок хранит строки так, чтобы находить нужные за миллисекунды даже среди миллионов записей. Внутри у неё индексы, журнал изменений и планировщик запросов, но снаружи всё это спрятано: ты пишешь вопрос на SQL — получаешь строки. SQL (Structured Query Language, язык структурированных запросов) — декларативный язык: ты описываешь, ЧТО хочешь получить, а движок сам решает, КАК это достать.

Первое знакомство обычно проходит через аналогию с Excel, и она правда помогает: таблицы, строки, колонки. Но аналогия врёт в трёх местах, и честнее знать об этом сразу.

  • Типы колонок честные: в колонке year лежат только целые числа, а не «что ввёл пользователь, лишь бы влезло».
  • Условия встроены в язык: «покажи строки, где цена между 400 и 700» — одна строчка SQL, а не ручной обход ячеек.
  • Миллионы строк — норма: Excel начинает задыхаться на сотнях тысяч, база с индексом находит строку среди миллионов так же быстро.

Дальше по курсу ты встретишь и вторую половину SQL — агрегаты и JOIN (уроки 6 и 7 раздела про SQL), но фундамент у всего один: создать таблицу, вставить строки, прочитать их. Этим и займёмся.

Чем SQLite отличается от MySQL?

Базы данных бывают двух архитектур. Серверные — MySQL, PostgreSQL — это отдельные программы, которые живут на машине (обычно другой), слушают порт и пускают к себе по логину и паролю. Встраиваемые — SQLite — это библиотека: весь движок лежит внутри твоего процесса, а база — обычный файл рядом с кодом. Ни установки, ни порта, ни пароля.

подключение: серверная база против SQLite
# Серверная база (MySQL) требует адрес, логин и пароль:
# import mysql.connector
# conn = mysql.connector.connect(
#     host="localhost",      # где живёт сервер
#     user="root",           # кто подключается
#     password="s3cret",     # пароль
#     database="library",    # какая база
# )

# SQLite: весь сервер уже внутри Python, нужен только путь к файлу:
import sqlite3

conn = sqlite3.connect("library.db")
Блок не запускается в браузере намеренно: mysql.connector — сторонний пакет, а сервера MySQL на странице нет. Это сравнение интерфейсов: у SQLite всё то же самое, но без церемоний.

Из-за простоты SQLite — самая массовая база в мире: она живёт в каждом смартфоне (Android и iOS), в браузерах, в мессенджерах. Для обучения, прототипов, настольных приложений и сайтов с небольшой нагрузкой её хватает с запасом. А язык SQL в ней тот же: запросы из этого курса работают и в PostgreSQL, отличия — в мелочах, и мы будем их отмечать.

СвойствоSQLiteMySQL / PostgreSQL
Установкауже встроена в Pythonотдельный сервер
Где лежат данныеодин файл рядом с кодомна сервере, доступ по сети
Подключениеsqlite3.connect(путь)host, порт, логин, пароль
Параллельные писателиодин в момент временимного, с блокировками строк
Для чегоучёба, приложения, встраиваниесервисы с большой нагрузкой

Что делает import sqlite3?

Модуль sqlite3 входит в стандартную библиотеку — pip не нужен, ничего качать не надо. Он даёт два главных класса: Connection (соединение с базой — файлом или памятью) и Cursor (рабочая рука, через которую уходят запросы и приходят строки). Посмотрим на них вживую.

первое соединение и первый курсор
import sqlite3

conn = sqlite3.connect(":memory:")
print(type(conn))
cur = conn.cursor()
print(type(cur))
conn.close()
Вывод
<class 'sqlite3.Connection'>
<class 'sqlite3.Cursor'>

Разбираем по строкам. sqlite3.connect(":memory:") открывает базу — строка ":memory:" означает «не в файле, а в оперативной памяти»: база живёт, пока открыто соединение, и исчезает вместе с ним. Для учёбы это идеальный вариант — каждый запуск блока начинается с чистого листа. conn.cursor() создаёт курсор, а conn.close() закрывает соединение: привычка закрывать его явно пригодится, когда база станет файлом на диске.

Что делает cursor и зачем он нужен?

Курсор — посредник между Python и SQL: метод execute() отправляет запрос движку, а методы fetchone(), fetchall() и fetchmany() забирают результаты. Можно представлять его указателем на текущую строку выдачи: запрос наполняет список строк, а fetch-методы читают его, сдвигая указатель. Забавная деталь, которая поначалу сбивает с толку: execute() возвращает не данные, а сам курсор — поэтому один и тот же объект.

execute возвращает сам курсор
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()

# execute возвращает не результат, а тот же курсор:
print(cur.execute("SELECT 40 + 2") is cur)

# поэтому fetchone можно вызвать сразу через точку:
print(cur.execute("SELECT 7 * 6").fetchone())
conn.close()
Вывод
True
(42,)

Как создать первую таблицу: CREATE TABLE?

Таблица в базе — как таблица в Excel, только с контрактом: у каждой колонки есть имя и тип, и двигаться колонки не могут. Создание таблицы — тоже SQL-запрос, CREATE TABLE. После него таблица существует — убедимся, спросив служебный каталог sqlite_master, где SQLite хранит список всех таблиц базы.

CREATE TABLE books и проверка в sqlite_master
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()

cur.execute("""
    CREATE TABLE books (
        id     INTEGER PRIMARY KEY,
        title  TEXT,
        author TEXT,
        year   INTEGER
    )
""")

# sqlite_master - служебный каталог: какие таблицы есть в базе
cur.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
print(cur.fetchall())
conn.close()
Вывод
[('books',)]

Читаем схему как контракт. id INTEGER PRIMARY KEY — уникальный номер каждой строки: SQLite сама будет присваивать 1, 2, 3… (подробно — в уроке 2 про типы и схему). title TEXT и author TEXT — строки, year INTEGER — целое. Многострочная строка в тройных кавычках — просто способ красиво оформить SQL; движку всё равно, в одну строку запрос или в четыре.

Как вставить и прочитать первые строки?

Пустая таблица — это только схема. Наполним её командой INSERT INTO ... VALUES и прочитаем командой SELECT: классический минимальный цикл жизни данных. Пока вставляем явно и id, и все значения — в третьем уроке научимся передавать данные через параметры, как это делают в настоящем коде.

INSERT и SELECT: первая пара запросов
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("""
    CREATE TABLE books (
        id     INTEGER PRIMARY KEY,
        title  TEXT,
        author TEXT,
        year   INTEGER
    )
""")

cur.execute("INSERT INTO books VALUES (1, 'Мастер и Маргарита', 'Булгаков', 1967)")
cur.execute("INSERT INTO books VALUES (2, 'Преступление и наказание', 'Достоевский', 1866)")

cur.execute("SELECT * FROM books")
for row in cur.fetchall():
    print(row)
conn.close()
Вывод
(1, 'Мастер и Маргарита', 'Булгаков', 1967)
(2, 'Преступление и наказание', 'Достоевский', 1866)

SELECT * FROM books читается по-русски так: «выбери все колонки (*) из таблицы books». Каждая строка приходит в Python кортежем — значения по порядку колонок, как договаривалась схема. С кортежами ты уже умеешь: индексируй, распаковывай, считай длину.

fetchall возвращает список кортежей
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("CREATE TABLE books (id INTEGER PRIMARY KEY, title TEXT, author TEXT, year INTEGER)")
cur.execute("INSERT INTO books VALUES (1, 'Мастер и Маргарита', 'Булгаков', 1967)")
cur.execute("INSERT INTO books VALUES (2, 'Преступление и наказание', 'Достоевский', 1866)")

cur.execute("SELECT * FROM books")
rows = cur.fetchall()

print(rows)        # список кортежей
print(len(rows))   # сколько строк вернул запрос
print(rows[0])     # первая строка - кортеж
print(rows[0][1])  # заголовок первой книги
conn.close()
Вывод
[(1, 'Мастер и Маргарита', 'Булгаков', 1967), (2, 'Преступление и наказание', 'Достоевский', 1866)]
2
(1, 'Мастер и Маргарита', 'Булгаков', 1967)
Мастер и Маргарита

Что значит :memory: и при чём тут файл?

Мы всё время писали connect(":memory:") — пора показать, что база SQLite это в первую очередь файл. Один вызов connect с путём — и на диске появляется библиотека: та же схема, те же запросы. Этот блок тоже настоящий: он создаёт файл, а в конце убирает его за собой.

база — это обычный файл на диске
import os
import sqlite3

DB = "library.db"
if os.path.exists(DB):
    os.remove(DB)            # начинаем с чистого листа

conn = sqlite3.connect(DB)   # база - файл рядом со скриптом
cur = conn.cursor()
cur.execute("CREATE TABLE books (id INTEGER PRIMARY KEY, title TEXT)")
cur.execute("INSERT INTO books (title) VALUES ('Евгений Онегин')")
conn.commit()                # сохраняем изменения в файл
conn.close()

print("Файл базы:", os.path.exists(DB))
os.remove(DB)                # убираем за собой
print("После удаления:", os.path.exists(DB))
Вывод
Файл базы: True
После удаления: False

Здесь появился новый метод — conn.commit(): он фиксирует изменения в файле. В базах в памяти от него ничего не видно, а вот с файлом без него данные не сохранятся — этому посвящён отдельный питфолл в уроке 3 про INSERT и SELECT. Кстати, файл library.db можно открыть любой SQLite-утилитой — внутри обычная база, никакого секретного формата.

Как выглядит код с базой в настоящем проекте?

Учебные блоки держат всё в одном месте, а в реальном проекте соединение открывают один раз, обкладывают его with и хранят схему отдельным модулем. Вот честный продакшн-фрагмент — он не запускается на странице, потому что пишет в файл твоего компьютера, но именно так выглядит работа с sqlite3 после этого курса.

продакшн-привычка: with и IF NOT EXISTS
import sqlite3

def get_connection(path):
    conn = sqlite3.connect(path)
    conn.execute("PRAGMA foreign_keys = ON")   # будем проверять связи - урок 7
    return conn

conn = get_connection("app.db")
with conn:                                     # with сделает commit (или откат)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS logs (
            id   INTEGER PRIMARY KEY,
            text TEXT
        )
    """)
    conn.execute("INSERT INTO logs (text) VALUES ('старт приложения')")
conn.close()
Сниппет для своего компьютера: он создаёт файл app.db на диске. В песочнице урока мы работаем с :memory:, поэтому блок не запускается — но все команды в нём тебе уже знакомы.

Новое здесь ровно два слова. IF NOT EXISTS — «не ругайся, если таблица уже создана»: при каждом старте программы схема проверяется, а не падает. with conn: — контекстный менеджер, который по выходу из блока делает commit (или откат при ошибке); закрывать соединение он не умеет, поэтому дальше стоит явный close(). Полный разбор транзакций — в девятом уроке.

Собираем всё вместе: мини-программа

Закрепим связку connect — cursor — CREATE — INSERT — SELECT в одной маленькой программе: музыкальный плейлист вместо книжной полки. Это последний блок урока с новым содержанием, дальше — проверь себя.

плейлист: полная последовательность
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()

cur.execute("CREATE TABLE tracks (id INTEGER PRIMARY KEY, title TEXT, minutes INTEGER)")
cur.execute("INSERT INTO tracks (title, minutes) VALUES ('Бустер', 4)")
cur.execute("INSERT INTO tracks (title, minutes) VALUES ('Прогулка по воде', 5)")
cur.execute("INSERT INTO tracks (title, minutes) VALUES ('Гуд-бай, Америка', 6)")

cur.execute("SELECT title, minutes FROM tracks")
for row in cur.fetchall():
    print(row)

cur.execute("SELECT COUNT(*) FROM tracks")
print("Всего треков:", cur.fetchone()[0])
conn.close()
Вывод
('Бустер', 4)
('Прогулка по воде', 5)
('Гуд-бай, Америка', 6)
Всего треков: 3

SELECT COUNT(*) FROM tracks — первое знакомство с агрегатной функцией: она считает строки и возвращает одну строку с одним числом. Разбор COUNT, SUM и AVG с группировкой — шестой урок курса, а пока просто запомни приём «посчитать, сколько всего».

Что дальше

Ты создал первую базу, понял роли Connection и Cursor, создал таблицу через CREATE TABLE и прошёл полный цикл: вставить строки — прочитать — посчитать. Следующий шаг — научиться проектировать схемы по-взрослому: в уроке 2 разбираем пять типов SQLite, ограничения NOT NULL, UNIQUE и DEFAULT и команду ALTER TABLE. А если хочется сразу увидеть, зачем всё это аналитику, загляни в первый урок Pandas: там данные уже лежат готовыми таблицами, и выученный SQL прицепится к ним через pd.read_sql.

SQL — самый долговечный навык программиста: язык почти не менялся за сорок лет, а нужен он аналитикам, бэкендерам и тестировщикам одинаково.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()
print(cur.execute("SELECT 10 - 3").fetchone())
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)")
cur.execute("INSERT INTO t (name) VALUES ('альфа')")
cur.execute("INSERT INTO t (name) VALUES ('бета')")

cur.execute("SELECT id, name FROM t")
rows = cur.fetchall()
print(len(rows))
print(rows[1][0])
import sqlite3

conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("CREATE TABLE t (x INTEGER)")
cur.execute("SELECT * FROM t")
print(cur.fetchall())
Проверь себя
0 / 5

1. Что означает строка ":memory:" в вызове sqlite3.connect(":memory:")?

2. Как правильно получить строки после cur.execute("SELECT * FROM books")?

3. Чем SQLite отличается от MySQL?

4. Что выведет print(cur.execute("SELECT 7 * 6")) без вызова fetch-метода?

5. Где SQLite хранит список всех таблиц базы?

Карточки терминов
Запомнено: 0 / 6
Практика

Создайте в памяти базу и таблицу films (id INTEGER PRIMARY KEY, title TEXT, director TEXT, year INTEGER). Вставьте два фильма: «Ирония судьбы» Рязанова 1975 года и «Кин-дза-дза!» Данелии 1986 года. Выведите все строки таблицы по одной — формат совпадает с заготовкой.

practice.py
Вопросы и ответы по уроку

Что такое SQLite и почему она уже есть в Python?

SQLite — встраиваемая база данных: весь движок собран как библиотека, которую встраивают в программу, поэтому в стандартный модуль sqlite3 она входит «из коробки» и не требует установки. База хранится в одном файле (или в памяти при ":memory:"), а язык запросов — обычный SQL, тот же, что в MySQL и PostgreSQL.

Нужно ли устанавливать сервер баз данных, чтобы начать?

Нет. Для этого курса не нужны ни MySQL, ни PostgreSQL: SQLite работает внутри Python, а на этой странице — внутри браузера через Pyodide. Каждый код-блок сам открывает базу, создаёт таблицу и выполняет запросы, так что старт вообще без установки чего-либо.

Что значит ":memory:" в sqlite3.connect?

Специальное имя, которое просит держать базу в оперативной памяти, а не в файле. База живёт, пока открыто соединение, и исчезает при close() — идеально для учёбы и тестов: каждый запуск начинается с чистого состояния. Для постоянного хранения передайте путь: sqlite3.connect("mydata.db").

Чем SQL отличается от Python?

Python — универсальный язык программирования: циклы, функции, классы. SQL — специализированный декларативный язык запросов к данным: вы описываете, какие строки нужны, а движок сам выбирает способ их достать. Они не конкуренты, а пара: Python готовит данные и логику, SQL быстро ищет и считает в базе.

Понравился урок? Сошлитесь на него

«База данных — это умный файл: движок хранит строки так, чтобы находить нужные за миллисекунды даже среди миллионов записей.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.