Практикум demo — авиакомпания PostgreSQL
Контекст: учебная база demo — открытый логический дамп для практики SQL. Предметная область — воображаемая авиакомпания: бронирования, билеты, рейсы, аэропорты. После 101 и 888 — лучший следующий шаг для JOIN, агрегатов и оконных функций на осмысленных данных.
См. также: JOIN — четыре типа на одном примере · Практикум shop_data · мета-команды psql
Установка базы demo
Официальные архивы — логический дамп pg_dump, восстанавливается через psql. Три размера (данные о полётах за 1 / 3 / 12 месяцев):
| Архив | Объём архива | Размер БД после restore |
|---|---|---|
| demo-small.zip | ~21 МБ | ~280 МБ |
| demo-medium.zip | ~62 МБ | ~702 МБ |
| demo-big.zip | ~232 МБ | ~2,6 ГБ |
Для первых запросов достаточно small; для экспериментов с планами и индексами — big.
Linux (от пользователя postgres):
sudo su - postgres
wget https://edu.postgrespro.ru/demo-small.zip
zcat demo-small.zip | psql
Windows. Скачайте архив, распакуйте SQL-файл (имя с датой среза, например demo-small-20170815.sql), положите в рабочую папку psql и выполните:
\i demo-small-20170815.sql
demo. Владельцем станет роль, под которой выполнялся restore.Подключение:
psql -U postgres -d demo
\c demo
SELECT bookings.now();
SELECT count(*) FROM flights;
Схема данных (схема bookings)
Все учебные объекты лежат в схеме bookings. При подключении к demo она в search_path, поэтому в запросах можно писать flights, а не bookings.flights.
| Таблица | Назначение |
|---|---|
| bookings | Бронирование (book_ref, дата, total_amount) |
| tickets | Билет на пассажира (ticket_no, passenger_name, …) |
| ticket_flights | Связь билет ↔ рейс, класс, стоимость перелёта |
| flights | Конкретный рейс (расписание, статус, фактические времена) |
| airports | Код IATA, город, coordinates (point), timezone |
| aircrafts | Модель ВС и дальность полёта |
| seats | Места в салоне по модели и классу обслуживания |
| boarding_passes | Посадочный талон (рейс, место, порядок посадки) |
Представления
flights_v— рейсы с расшифровкой аэропортов, локальным временем и длительностью полёта (\d+ flights_v).routes— «маршрут без даты»: номер рейса, аэропорты, модель, массив дней неделиdays_of_week, плановаяduration.
Служебное
bookings.now()— фиксированный «момент среза» дампа (какnow()в учебных запросах). В small-дампе срез — 2017-08-15.- Параметр
bookings.lang(ru/en) — язык названий городов и моделей:ALTER DATABASE demo SET bookings.lang = 'en';затем\c.
Подробное описание столбца — \d+ имя_таблицы в psql.
Базовые запросы
Справочники
SELECT airport_code, city FROM airports LIMIT 5;
SELECT aircraft_code, model, range FROM aircrafts ORDER BY range DESC;
JOIN — рейсы с городами
SELECT f.flight_no,
f.scheduled_departure,
da.city AS from_city,
aa.city AS to_city
FROM flights f
JOIN airports da ON da.airport_code = f.departure_airport
JOIN airports aa ON aa.airport_code = f.arrival_airport
WHERE f.scheduled_departure::date = bookings.now()::date
LIMIT 10;
Тот же смысл короче через представление:
SELECT flight_no, departure_city, arrival_city, scheduled_departure
FROM flights_v
WHERE scheduled_departure::date = bookings.now()::date
LIMIT 10;
Агрегаты и GROUP BY
Сколько билетов в каждом бронировании:
SELECT cnt, count(*) AS bookings_count
FROM (
SELECT book_ref, count(*) AS cnt
FROM tickets
GROUP BY book_ref
) tt
GROUP BY cnt
ORDER BY cnt;
Доля пассажиров по фамилии (оконная функция):
SELECT passenger_name,
round(100.0 * cnt / sum(cnt) OVER (), 2) AS percent
FROM (
SELECT passenger_name, count(*) AS cnt
FROM tickets
GROUP BY passenger_name
) t
ORDER BY percent DESC
LIMIT 10;
Задержки рейсов
SELECT f.flight_no,
f.scheduled_departure,
f.actual_departure,
f.actual_departure - f.scheduled_departure AS delay
FROM flights f
WHERE f.actual_departure IS NOT NULL
ORDER BY delay DESC
LIMIT 10;
NOT EXISTS — свободные места на рейсе
SELECT count(*) AS free_seats
FROM flights f
JOIN seats s ON s.aircraft_code = f.aircraft_code
WHERE f.flight_no = 'PG0404'
AND f.scheduled_departure::date = bookings.now()::date - INTERVAL '1 day'
AND NOT EXISTS (
SELECT NULL
FROM boarding_passes bp
WHERE bp.flight_id = f.flight_id
AND bp.seat_no = s.seat_no
);
Расстояние между аэропортами
Задача — расстояние KGD (Калининград) и PKC (Петропавловск-Камчатский). Координаты в airports.coordinates; для сферической модели достаточно расширений cube и earthdistance:
CREATE EXTENSION IF NOT EXISTS cube;
CREATE EXTENSION IF NOT EXISTS earthdistance;
SELECT round(
(a_from.coordinates <@> a_to.coordinates) * 1.609344
) AS km
FROM airports a_from,
airports a_to
WHERE a_from.airport_code = 'KGD'
AND a_to.airport_code = 'PKC';
Оператор <@> даёт расстояние в милях; множитель 1.609344 переводит в километры. Для продакшена с геодезической точностью смотрите PostGIS — в 888 и справочнике.
Задания для самопроверки
- Список аэропортов России (
cityили код страны в данных) с числом исходящих рейсов за «сегодня» (bookings.now()). - Топ-5 маршрутов (
departure_airport→arrival_airport) по числу рейсов за последние 7 дней отbookings.now(). - Пассажиры, зарегистрировавшиеся первыми (
boarding_no = 1) более чем на одном рейсе (подсказка —GROUP BY+HAVING). - Граф рейсов — пары аэропортов, между которыми есть хотя бы один рейс в
routesилиflights(можно начать сSELECT DISTINCT departure_airport, arrival_airport FROM routes). - Переключите
bookings.langнаen, переподключитесь (\c) и сравните выводSELECT city FROM airports LIMIT 5.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Вот SQL как раз обеспечивает такую связь и это главное отличие реляционных БД - реляции (relations), что означает связи. Знакомимся с языком - ставим программы, запускаем, выполняем первые запросы. От файлового хранения к реляционной и современной мультимодельной СУБД — термины, причины появления SQL и базовая классификация систем. Домены, атрибуты, кортежи и отношения — свойства реляционных таблиц и ограничения целостности при проектировании схемы. Функциональные зависимости, нормальные формы 1НФ–4НФ и НФБК, аномалии обновления и осознанная денормализация при проектировании схемы. Метаданные СУБД через information_schema и pg_catalog — запросы к структуре таблиц, ключей и индексов в PostgreSQL. Логическое и физическое резервное копирование, pg_dump, pg_restore, WAL и восстановление на точку во времени (PITR). Логический порядок выполнения SELECT, проекция, WHERE, DISTINCT, ORDER BY и правила читаемого форматирования запросов. Скалярные и коррелированные подзапросы, EXISTS против IN, особенности NULL и выбор между подзапросом и JOIN. AND, OR, NOT, приоритет операторов, NULL и UNKNOWN, IS NULL, NOT IN и IS DISTINCT FROM в PostgreSQL. MVCC, уровни блокировок таблиц, FOR UPDATE, SKIP LOCKED, взаимоблокировки и диагностика через pg_locks. Учебная схема интернет-магазина для PostgreSQL — DDL и примеры запросов по темам курса SQL.SQL - язык структурированных запросов
Первые шаги с SQL
Эволюция систем хранения данных
Реляционная модель данных
Нормализация данных
Словарь данных и системные каталоги
Резервное копирование и восстановление PostgreSQL
Оператор SELECT — синтаксис и стиль
Подзапросы, EXISTS и IN
Фильтрация и трёхзначная логика
Блокировки и конкурентный доступ в PostgreSQL
Практикум shop_data