Files
digitalization-2026-10/README.md
T

430 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Учебный кейс «Учёт газоперекачивающих агрегатов и результатов осмотров»
## 1. Описание ситуации
На двух компрессорных станциях эксплуатируются газоперекачивающие агрегаты (ГПА). Сотрудники проводят осмотры и фиксируют результат: «Без замечаний» или «Есть замечания», при необходимости добавляют комментарий.
Сведения ведутся в общей электронной таблице: названия станций и оборудования повторяются в каждой строке. Необходимо создать небольшую базу данных, чтобы исключить лишнее повторение сведений и получать ответы на вопросы руководителя.
Все названия, записи и результаты осмотров вымышлены. Кейс не предназначен для диагностики оборудования.
## 2. Что должна позволять база данных
- Хранить перечень станций и установленного оборудования.
- Регистрировать осмотры.
- Находить осмотры с замечаниями.
- Получать сводку по каждой станции.
## 3. Структура данных
В учебной модели три таблицы:
| Таблица | Что хранится | Поля |
|---|---|---|
| `stations` | Компрессорные станции | `station_id`, `name` |
| `units` | Газоперекачивающие агрегаты | `unit_id`, `station_id`, `inventory_no`, `commissioned_year` |
| `inspections` | История осмотров | `inspection_id`, `unit_id`, `inspection_date`, `result`, `comment` |
`id` — идентификатор записи. Первичный ключ однозначно определяет запись; внешний ключ связывает её с записью другой таблицы.
```text
Компрессорная станция (1) ── (N) Агрегат (1) ── (N) Осмотр
```
Одна станция может содержать несколько агрегатов; у агрегата может быть несколько осмотров. В этом кейсе агрегат закреплён за одной станцией. Историю перемещений, сотрудников, ремонты и датчики не рассматриваем.
Исходные данные: 2 станции, 4 агрегата, 6 осмотров. Данные для загрузки приведены в SQL и JSON ниже — создавать их самостоятельно не требуется.
## 4. Создание диаграммы — готовый код
Выполните этот шаг до перехода к SQL-заданиям.
1. Откройте [генератор диаграмм dbdiagram](https://dbdiagram.io/erd-generator).
2. Найдите редактор схемы. Выберите DBML, если сервис предлагает выбор формата.
3. Удалите демонстрационный пример и вставьте весь код из блока ниже. Строки с обозначением языка блока копировать не нужно: копируйте только сам код.
4. Схема должна появиться рядом с редактором. При необходимости перейдите из страницы генератора в интерактивный редактор по предложенной сервисом ссылке.
5. Найдите три таблицы и две линии связей. Сохраните скриншот диаграммы.
DBML — текстовое описание структуры. Этот код рисует диаграмму, но не создаёт таблицы в PostgreSQL. Регистрация для просмотра интерактивной ERD по описанию сервиса не требуется; дополнительные функции полного редактора могут требовать учётную запись.
```dbml
Table stations {
station_id integer [pk, note: 'Идентификатор станции']
name text [not null, note: 'Название станции']
Note: 'Компрессорные станции'
}
Table units {
unit_id integer [pk, note: 'Идентификатор агрегата']
station_id integer [not null, note: 'Станция установки']
inventory_no text [not null, unique, note: 'Инвентарный номер']
commissioned_year integer [not null, note: 'Год ввода в эксплуатацию']
Note: 'Газоперекачивающие агрегаты'
}
Table inspections {
inspection_id integer [pk, note: 'Идентификатор осмотра']
unit_id integer [not null, note: 'Осмотренный агрегат']
inspection_date date [not null, note: 'Дата осмотра']
result text [not null, note: 'Без замечаний или Есть замечания']
comment text [note: 'Комментарий']
Note: 'Журнал осмотров'
}
Ref: units.station_id > stations.station_id
Ref: inspections.unit_id > units.unit_id
```
Проверьте результат:
- В `units` поле `station_id` связано с `stations.station_id`.
- В `inspections` поле `unit_id` связано с `units.unit_id`.
- Название станции не дублируется в каждой строке осмотра.
Три уровня проектирования на этом примере:
- Концептуальный: станция, агрегат, осмотр и связи между ними.
- Логический: атрибуты, идентификаторы и структура связей.
- Физический: конкретные таблицы, типы данных и ограничения PostgreSQL в следующем разделе.
Диаграмма выше показывает уже детализированную структуру; для каждого уровня отдельную диаграмму строить не требуется.
## 5. Создание и заполнение базы PostgreSQL
1. Откройте [Aiven PostgreSQL Playground](https://aiven.io/tools/pg-playground).
2. Перейдите к SQL-редактору, удалите демонстрационный код.
3. Вставьте весь следующий SQL-скрипт и выполните его кнопкой запуска в интерфейсе.
4. Дождитесь завершения без ошибок.
5. Сохраните скрипт у себя в текстовом файле. Не обновляйте и не закрывайте вкладку во время работы.
> Внимание: первые три команды удаляют учебные таблицы и их содержимое. Скрипт нужен для первоначального создания БД и возврата к исходным данным. Не применяйте его к реальной рабочей базе.
```sql
DROP TABLE IF EXISTS inspections;
DROP TABLE IF EXISTS units;
DROP TABLE IF EXISTS stations;
CREATE TABLE stations (
station_id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE units (
unit_id INTEGER PRIMARY KEY,
station_id INTEGER NOT NULL REFERENCES stations(station_id),
inventory_no TEXT UNIQUE NOT NULL,
commissioned_year INTEGER NOT NULL
);
CREATE TABLE inspections (
inspection_id INTEGER PRIMARY KEY,
unit_id INTEGER NOT NULL REFERENCES units(unit_id),
inspection_date DATE NOT NULL,
result TEXT NOT NULL CHECK (result IN ('Без замечаний', 'Есть замечания')),
comment TEXT
);
INSERT INTO stations (station_id, name) VALUES
(1, 'КС «Северная»'),
(2, 'КС «Южная»');
INSERT INTO units (unit_id, station_id, inventory_no, commissioned_year) VALUES
(1, 1, 'ГПА-001', 2018),
(2, 1, 'ГПА-002', 2020),
(3, 2, 'ГПА-003', 2019),
(4, 2, 'ГПА-004', 2022);
INSERT INTO inspections (inspection_id, unit_id, inspection_date, result, comment) VALUES
(1, 1, '2026-10-20', 'Без замечаний', 'Видимых замечаний нет'),
(2, 2, '2026-10-20', 'Есть замечания', 'Повреждена маркировка'),
(3, 3, '2026-10-20', 'Есть замечания', 'Зафиксирован посторонний шум'),
(4, 4, '2026-10-20', 'Без замечаний', 'Видимых замечаний нет'),
(5, 2, '2026-10-21', 'Без замечаний', 'Маркировка восстановлена'),
(6, 3, '2026-10-21', 'Есть замечания', 'Требуется дополнительная проверка');
```
### Проверка загрузки
Замените текст в редакторе проверочным запросом и выполните его. Выполненный код создания не нужно повторять перед каждым запросом; при необходимости сохраните его отдельно и оставляйте в редакторе только текущий запрос.
```sql
SELECT 'stations' AS table_name, COUNT(*) AS row_count FROM stations
UNION ALL
SELECT 'units', COUNT(*) FROM units
UNION ALL
SELECT 'inspections', COUNT(*) FROM inspections;
```
Ожидается: `stations` — 2, `units` — 4, `inspections` — 6.
Если после очистки редактора сервис начинает новую сессию и таблицы недоступны, используйте в одном запуске исходный скрипт и текущий запрос; учитывайте, что это каждый раз сбрасывает внесённые изменения. Для заданий добавления и исправления записи выполняйте все связанные команды вместе после исходного скрипта. Резервная площадка — [db<>fiddle](https://dbfiddle.uk/), выберите PostgreSQL: создание и загрузку поместите в первый блок, запросы — в следующие.
## 6. Работа с реляционной базой: задания с решениями
Сначала выполните задания 1–6 на исходных данных. Затем переходите к добавлению и изменению записей. Каждый блок ниже можно скопировать в SQL-редактор.
### Задание 1. Просмотреть все агрегаты
Решение:
```sql
SELECT *
FROM units
ORDER BY unit_id;
```
Ожидаемый результат и объяснение: Появятся четыре строки: ГПА-001, ГПА-002, ГПА-003 и ГПА-004. `SELECT` означает «выбрать», `*` — все столбцы, `FROM` — из какой таблицы.
### Задание 2. Найти агрегаты, введённые после 2019 года
Решение:
```sql
SELECT inventory_no, commissioned_year
FROM units
WHERE commissioned_year > 2019
ORDER BY inventory_no;
```
Ожидаемый результат и объяснение: Две строки: ГПА-002 — 2020; ГПА-004 — 2022. `WHERE` задаёт условие. Значение 2019 не включается.
### Задание 3. Найти осмотры с замечаниями
Решение:
```sql
SELECT inspection_id, unit_id, inspection_date, comment
FROM inspections
WHERE result = 'Есть замечания'
ORDER BY inspection_id;
```
Ожидаемый результат и объяснение: Три записи: осмотры № 2, 3 и 6. Это число событий, а не число неисправных агрегатов.
### Задание 4. Показать станцию каждого агрегата
Решение:
```sql
SELECT u.inventory_no, s.name AS station
FROM units AS u
JOIN stations AS s ON s.station_id = u.station_id
ORDER BY u.inventory_no;
```
Ожидаемый результат и объяснение: ГПА-001 и ГПА-002 относятся к КС «Северная», ГПА-003 и ГПА-004 — к КС «Южная». `JOIN` соединяет таблицы, `ON` указывает связь. `u` и `s` — короткие обозначения таблиц, `AS station` — подпись столбца результата.
### Задание 5. Получить подробный список замечаний
Решение:
```sql
SELECT i.inspection_date,
s.name AS station,
u.inventory_no,
i.comment
FROM inspections AS i
JOIN units AS u ON u.unit_id = i.unit_id
JOIN stations AS s ON s.station_id = u.station_id
WHERE i.result = 'Есть замечания'
ORDER BY i.inspection_date, u.inventory_no;
```
Ожидаемый результат и объяснение: Три строки: ГПА-002 на КС «Северная» — 20.10.2026; ГПА-003 на КС «Южная» — 20.10.2026 и 21.10.2026. Название станции получено через две связи.
### Задание 6. Получить сводку по всем станциям
Решение:
```sql
SELECT s.name AS station,
COUNT(i.inspection_id) AS inspections_total,
SUM(CASE WHEN i.result = 'Есть замечания'
THEN 1 ELSE 0 END) AS inspections_with_remarks
FROM stations AS s
LEFT JOIN units AS u ON u.station_id = s.station_id
LEFT JOIN inspections AS i ON i.unit_id = u.unit_id
GROUP BY s.station_id, s.name
ORDER BY s.station_id;
```
Ожидаемый результат и объяснение: КС «Северная»: всего 3 осмотра, с замечаниями 1. КС «Южная»: всего 3 осмотра, с замечаниями 2. `GROUP BY` объединяет записи по станции. `COUNT` считает осмотры. `SUM(CASE ...)` считает только записи с замечаниями. `LEFT JOIN` позволяет сохранить в отчёте даже станцию без осмотров.
### Задание 7. Зарегистрировать новый осмотр
Добавьте осмотр ГПА-001 от 22.10.2026. В комментарии специально оставлена опечатка для следующего задания.
```sql
INSERT INTO inspections
(inspection_id, unit_id, inspection_date, result, comment)
VALUES
(7, 1, '2026-10-22', 'Без замечаний', 'Осмотр заврешён');
SELECT * FROM inspections WHERE inspection_id = 7;
```
Ожидается новая запись № 7. Общее число осмотров увеличится с 6 до 7. Этот `INSERT` выполняйте один раз: повторная вставка того же идентификатора вызовет ошибку первичного ключа.
### Задание 8. Исправить комментарий
```sql
UPDATE inspections
SET comment = 'Осмотр завершён'
WHERE inspection_id = 7;
SELECT * FROM inspections WHERE inspection_id = 7;
```
Ожидается: у записи № 7 комментарий «Осмотр завершён». `UPDATE` изменяет запись, `WHERE` ограничивает изменение конкретной записью. Не убирайте условие: иначе комментарий изменится у всех осмотров.
Повторите сводку из задания 6. После добавления осмотра у КС «Северная» будет 4 осмотра, из них 1 с замечаниями; у КС «Южная» — 3 и 2 соответственно.
## 7. Работа с документной моделью: задания с решениями
Используем тот же исходный набор из шести осмотров, до добавления записи № 7. Здесь каждый осмотр — отдельный документ. Название станции и номер агрегата записаны прямо внутри него. Это альтернативная учебная модель с намеренным повторением части сведений.
### Шаг 1. Загрузить документы
1. Откройте [Mongo Playground](https://mongoplayground.net/).
2. Выберите режим `single collection` и формат `bson`, если предлагается выбор.
3. В поле `Database` удалите пример и вставьте весь массив ниже.
4. В поле `Query` вставьте запрос из следующего шага.
5. Выполните запрос командой запуска в интерфейсе или сочетанием `Ctrl + Enter` (`Cmd + Enter` на macOS).
Поле Database задаёт исходные документы песочницы. Команда SQL или `insertMany()` здесь не нужна.
```json
[
{
"inspection_id": 1,
"date": "2026-10-20",
"station": "КС «Северная»",
"unit": "ГПА-001",
"result": "Без замечаний",
"details": {
"observation": "Видимых замечаний нет"
}
},
{
"inspection_id": 2,
"date": "2026-10-20",
"station": "КС «Северная»",
"unit": "ГПА-002",
"result": "Есть замечания",
"details": {
"observation": "Повреждена маркировка"
}
},
{
"inspection_id": 3,
"date": "2026-10-20",
"station": "КС «Южная»",
"unit": "ГПА-003",
"result": "Есть замечания",
"details": {
"observation": "Зафиксирован посторонний шум"
}
},
{
"inspection_id": 4,
"date": "2026-10-20",
"station": "КС «Южная»",
"unit": "ГПА-004",
"result": "Без замечаний",
"details": {
"observation": "Видимых замечаний нет"
}
},
{
"inspection_id": 5,
"date": "2026-10-21",
"station": "КС «Северная»",
"unit": "ГПА-002",
"result": "Без замечаний",
"details": {
"observation": "Маркировка восстановлена"
}
},
{
"inspection_id": 6,
"date": "2026-10-21",
"station": "КС «Южная»",
"unit": "ГПА-003",
"result": "Есть замечания",
"details": {
"observation": "Требуется дополнительная проверка"
}
}
]
```
### Шаг 2. Показать все осмотры
Вставьте в поле Query:
```javascript
db.collection.find({})
```
Ожидается: 6 документов. Дата в примере хранится строкой `YYYY-MM-DD`, а не специальным типом даты MongoDB.
### Шаг 3. Найти осмотры с замечаниями
```javascript
db.collection.find({
"result": "Есть замечания"
})
```
Ожидается: 3 документа — `inspection_id` 2, 3 и 6.
### Шаг 4. Найти историю выбранного агрегата
```javascript
db.collection.find({
"unit": "ГПА-003"
})
```
Ожидается: 2 документа — осмотры № 3 и 6.
### Шаг 5. Добавить поле к одному исходному документу
В поле Database найдите первый документ (`inspection_id` 1). После строки `"inspection_id": 1,` добавьте строку:
```json
"photo": "inspection_01.jpg",
```
Не удаляйте запятые между полями. Затем выполните:
```javascript
db.collection.find({
"inspection_id": 1
})
```
Ожидается: документ № 1 с новым полем `photo`. Оно содержит имя файла, не саму фотографию. Это редактирование исходного набора песочницы; изменение записи командой СУБД в реляционной части показано отдельно через `UPDATE`.
### Шаг 6. Получить сводку по замечаниям
Дополнительное задание; если времени недостаточно, его демонстрирует преподаватель.
```javascript
db.collection.aggregate([
{ "$match": { "result": "Есть замечания" } },
{ "$group": { "_id": "$station", "remarks_count": { "$sum": 1 } } },
{ "$sort": { "_id": 1 } }
])
```
Ожидается: КС «Северная» — 1; КС «Южная» — 2. `$match` отбирает документы, `$group` объединяет по станции, `$sum` считает, `$sort` упорядочивает. В этой сводке появятся только станции, у которых есть замечания; станции без замечаний она не выводит.
## 8. Ссылки на инструменты
- [dbdiagram: генератор диаграмм](https://dbdiagram.io/erd-generator) — описание сервиса подтверждает приём DBML и SQL.
- [PostgreSQL Playground](https://aiven.io/tools/pg-playground).
- [Mongo Playground](https://mongoplayground.net/).
- [Документация Mongo Playground](https://mongoplayground.net/static/docs-8.html).
- [Резервная SQL-площадка db<>fiddle](https://dbfiddle.uk/).