База данных учебных курсов и заявок
В базе всё просто: есть курсы (в таблице Course) и заявки людей на эти курсы (в таблице Application). У каждой заявки указан ровно один курс, а значит, один курс может иметь много заявок — это связь 1 : N («один ко многим»). Все данные ниже настоящие — их получили из реально запущенной базы, ничего не выдумано.
Схема базы данных
Заявки по статусам
Заявки по курсам
С чего начать
4 шага по одному клику — от «что это за база» до «как выглядит код».
Две таблицы и все их колонки — с простыми объяснениями.
Почему заявка всегда относится к курсу и что значит каскад.
Настоящие записи курсов и заявок — можно искать и сортировать.
Весь код проекта — нажми на слово, узнаешь, что оно значит.
Словарик новичка
Слова из отчёта — простыми словами и с примером из жизни. Нажми на слово со значком — появится подсказка.
Таблицы и колонки
В базе две таблицы — как две папки: в одной курсы, во второй заявки. Нажми на таблицу — откроется карточка со вкладками. Нажми на любую колонку — узнаешь, зачем она нужна и что в ней хранится.
Связи: как таблицы связаны
Связь одна: Course (1) —< Application (N). Это значит: один курс — много заявок. Заявка всегда «ссылается» на конкретный курс. Ниже — объяснение по шагам и живой пример.
Связь · FK_Application_Course
Нажми, чтобы открыть подробное объяснение →
Как работает связь — по шагам
Course.CourseId — «паспорт» курса: у каждого курса свой номер, двух одинаковых не бывает.
Application.CourseId — номер курса, на который подана заявка. Такого номера нет в Course — заявка «повиснет в воздухе».
База сама проверяет каждую новую заявку: если такого курса не существует — заявку добавить не даст.
Один и тот же номер курса может стоять у многих заявок — отсюда и название «один ко многим».
Удалили курс — его заявки удалятся сами, никто не останется без курса. Поменялся номер курса — он сам поменяется у всех заявок.
Один курс → несколько заявок
Выбери курс ниже — заявки, связанные с ним, подсветятся.
Данные из отчёта
Здесь — настоящие данные: 4 курса и 11 заявок. Нажми на курс — увидишь его заявки. Нажми на заявку — увидишь её курс. Можно искать, сортировать и фильтровать.
Информация о записи
Выбери строку в таблице выше — здесь появятся подробности и связанные записи.
Связанные записи
Выбери курс, чтобы увидеть его заявки, или заявку, чтобы увидеть её курс.
SQL-запросы и код проекта
Код всех 8 файлов проекта — такой же, как в базе. Нажми на подсвеченное слово (например PRIMARY KEY или CHECK) — появится простое объяснение, что оно значит.
Ограничения
Это правила для данных. Например: «цена не бывает отрицательной». Нажми на правило — увидишь пример хорошего и плохого значения и что случится, если его нарушить.
Индексы
Индексы — это «ускорители» базы: по ним компьютер быстрее находит нужные записи. Всего их 7. Нажми на карточку — узнаешь, что ускоряет каждый.
Результаты тестирования
Базу создавали с нуля три раза подряд — и каждый раз без ни одной ошибки. Все 13 правил базы проверили «на плохих данных» — все сработали как надо. Ниже — живое доказательство: настоящий вывод из терминала.
Базу создавали с нуля 3 раза подряд — все 3 раза без ни одной ошибки.
База жила в «коробке» Docker — как маленький компьютер внутри большого.
Одни и те же команды можно запускать снова — копии и дубли не появляются.
Заявку со статусом «отклонена» или «отменена» нельзя вернуть в работу — это защита от ошибок.
Как это выглядело в терминале (настоящий вывод)
================================================================
1. СТРУКТУРА ТАБЛИЦ
================================================================
TableName Pos ColumnName DataType MaxBytes Nullable DefaultValue
--------- --- ---------- -------- -------- -------- ------------
Application 1 ApplicationId int 4 0 NULL
Application 2 CourseId int 4 0 NULL
Application 3 ApplicantName nvarchar 300 0 NULL
Application 4 Phone nvarchar 64 0 NULL
Application 5 Email nvarchar 508 0 NULL
Application 6 PreferredStartDate date 3 0 NULL
Application 7 Status ApplicationStatus (alias-тип) 0 ('new')
Application 8 CreatedAt datetime2 7 0 (sysutcdatetime())
Application 9 Comment nvarchar 2000 1 NULL
Course 1 CourseId int 4 0 NULL
Course 2 Title nvarchar 400 0 NULL
Course 3 DurationHours int 4 0 NULL
Course 4 Price decimal 9 0 NULL
Course 5 IsActive bit 1 0 ((1))
Course 6 CreatedAt datetime2 7 0 (sysutcdatetime())
================================================================
2. СВЯЗЬ 1:N (Course -> Application)
================================================================
ForeignKey ChildTable ChildColumn ParentTable ParentColumn OnDelete
---------- ---------- ----------- ----------- ------------ --------
FK_Application_Course Application CourseId Course CourseId CASCADE
================================================================
3. ОГРАНИЧЕНИЯ (CHECK / PK / UNIQUE)
================================================================
ConstraintName Type TableName
-------------- ---- ---------
CK_Application_ApplicantName_NotBlank CHECK_CONSTRAINT Application
CK_Application_Email_Format CHECK_CONSTRAINT Application
CK_Application_Email_NotBlank CHECK_CONSTRAINT Application
CK_Application_Phone_Format CHECK_CONSTRAINT Application
CK_Application_Phone_NotBlank CHECK_CONSTRAINT Application
CK_Application_StartDate_NotPast CHECK_CONSTRAINT Application
CK_Application_Status_Valid CHECK_CONSTRAINT Application
CK_Course_DurationHours_Positive CHECK_CONSTRAINT Course
CK_Course_Price_NonNegative CHECK_CONSTRAINT Course
CK_Course_Title_NotBlank CHECK_CONSTRAINT Course
FK_Application_Course FOREIGN_KEY_CONSTRAINT Application
PK_Application PRIMARY_KEY_CONSTRAINT Application
PK_Course PRIMARY_KEY_CONSTRAINT Course
================================================================
4. ИНДЕКСЫ
================================================================
TableName IndexName Type IsUnique Filtered KeyColumns
--------- --------- ---- -------- -------- ----------
Application IX_Application_CourseId NONCLUSTERED 0 0 CourseId
Application IX_Application_CreatedAt NONCLUSTERED 0 0 CreatedAt
Application IX_Application_Status_CourseId NONCLUSTERED 0 0 Status, CourseId
Application PK_Application CLUSTERED 1 0 ApplicationId
Course IX_Course_IsActive NONCLUSTERED 0 0 IsActive
Course PK_Course CLUSTERED 1 0 CourseId
Course UX_Course_Active_Title NONCLUSTERED 1 1 Title
-- Объём данных:
Courses Applications
------- ------------
4 11
================================================================
ЗАДАНИЕ 4.1 Активные курсы с количеством заявок
================================================================
CourseId Title DurationHours Price ApplicationCount NewCount InProgressCount ApprovedCount RejectedCount
-------- ----- ------------- ----- ---------------- -------- --------------- ------------- -------------
1 Python для начинающих 40 25000.00 5 1 2 1 1
4 Английский язык (B2) 96 18000.00 2 1 0 0 0
3 Веб-разработка на C# 72 55000.00 2 0 1 1 0
2 Основы SQL и проектирование БД 32 30000.00 2 2 0 0 0
================================================================
ЗАДАНИЕ 4.2 Заявки со статусом "новая" для конкретного курса
================================================================
ApplicationId CourseId CourseTitle ApplicantName Phone Email PreferredStartDate Comment CreatedAt
------------- -------- ----------- ------------- ----- ----- ------------------ ------- ---------
6 2 Основы SQL и проектирование БД Волков Игорь +7 911 222-33-44 i.volkov@example.com 2026-10-12 NULL 2026-09-28 12:40:02.332
5 2 Основы SQL и проектирование БД Смирнова Екатерина +7 925 444-55-66 e.smirnova@example.com 2026-10-12 NULL 2026-09-28 12:40:02.332
================================================================
ЗАДАНИЕ 4.3 Полная информация о заявке + данные курса (JOIN)
================================================================
ApplicationId ApplicantName Phone Email PreferredStartDate Status Comment ApplicationCreatedAt CourseId CourseTitle CourseDurationHours CoursePrice CourseIsActive CourseCreatedAt
------------- ------------- ----- ----- ------------------ ------ ------- -------------------- -------- ----------- ------------------- ----------- -------------- ---------------
1 Иванова Мария Петровна +7 999 123-45-67 maria.ivanova@example.com 2026-10-19 in_progress NULL 2026-09-28 12:40:02.332 1 Python для начинающих 40 25000.00 1 2026-09-28 12:40:02.300
================================================================
ДОПОЛНИТЕЛЬНО: сводка по статусам + выручка
================================================================
Title Total NewCnt InProgressCnt ApprovedCnt RejectedCnt CancelledCnt
----- ----- ------ ------------- ----------- ----------- ------------
Python для начинающих 5 1 2 1 1 0
Английский язык (B2) 2 1 0 0 0 1
Веб-разработка на C# 2 0 1 1 0 0
Основы SQL и проектирование БД 2 2 0 0 0 0
Title ApprovedCnt Price Revenue
----- ----------- ----- -------
Веб-разработка на C# 1 55000.00 55000.00
Python для начинающих 1 25000.00 25000.00
================================================================
CRUD: создание заявки -> смена статуса -> удаление
================================================================
ApplicationId CourseId ApplicantName Phone Email PreferredStartDate Status CreatedAt Comment
------------- -------- ------------- ----- ----- ------------------ ------ --------- -------
21 1 Демонстрация Иванова +7 999 555-33-22 demo.showcase@example.com 2026-10-28 new 2026-09-28 12:40:02.723 заявка из демонстрации
-- создана заявка, Status по умолчанию = new
ApplicationId Status CreatedAt
------------- ------ ---------
21 in_progress 2026-09-28 12:40:02.723
-- статус изменён на in_progress
ApplicationId Status CreatedAt
------------- ------ ---------
21 rejected 2026-09-28 12:40:02.723
-- заявка отклонена
-- защита сработала: Нельзя изменить статус закрытой заявки.
-- заявка удалена
================================================================
ПРОВЕРКА ОГРАНИЧЕНИЙ (ожидаются срабатывания на мусоре)
================================================================
OK | Price >= 0 -> The INSERT statement conflicted with the CHECK constraint "CK_Course_Price_NonNegative". The conflict occurred in database "CourseManagement", table "dbo.Course", column 'Price'.
OK | FK защищает -> The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Application_Course". The conflict occurred in database "CourseManagement", table "dbo.Course", column 'CourseId'.
OK | Формат e-mail -> The INSERT statement conflicted with the CHECK constraint "CK_Application_Email_Format". The conflict occurred in database "CourseManagement", table "dbo.Application", column 'Email'.
OK | Список статусов -> The INSERT statement conflicted with the CHECK constraint "CK_Application_Status_Valid". The conflict occurred in database "CourseManagement", table "dbo.Application", column 'Status'.
OK | Дата не в прошлом -> The INSERT statement conflicted with the CHECK constraint "CK_Application_StartDate_NotPast". The conflict occurred in database "CourseManagement", table "dbo.Application", column 'PreferredStartDate'.