Навигация по курсу

На телефоне широкие таблицы и схемы прокручивайте влево и вправо.

УПРАВЛЕНИЕ ДАННЫМИ

Группа ВО-ИСИТ-31 · преподаватель Абрамов М.А.

3 курс · осенний семестр 2026/27

16 лекций · 32 ак. ч.24 лабораторные · 48 ак. ч.
Неделя 1 · 8–13 сентября 2026
ДатаДеньВремяТипТемаОткрыть
08.09Вт16:00–17:35ЛекцияЛ.1. Основные понятия баз данных и СУБД
Неделя 2 · 14–20 сентября 2026
ДатаДеньВремяТипТемаОткрыть
15.09Вт12:30–14:05Лаб.ЛР №1. SSMS: системные и учебные БД
16.09Ср14:15–15:50ЛекцияЛ.2. Реляционная модель. Функциональные зависимости
16.09Ср16:00–17:35Лаб.ЛР №2. Таблицы и первый SELECT
Неделя 3 · 21–27 сентября 2026
ДатаДеньВремяТипТемаОткрыть
22.09Вт14:15–15:50ЛекцияЛ.3. Нормализация. Аномалии обновления
22.09Вт16:00–17:35Лаб.ЛР №3. DDL: CREATE, типы, ограничения
23.09Ср12:30–14:05Лаб.ЛР №4. FK, ALTER TABLE, GO
Неделя 4 · 28 сентября – 4 октября 2026
ДатаДеньВремяТипТемаОткрыть
29.09Вт12:30–14:05ЛекцияЛ.4. Многопользовательские и распределённые БД
29.09Вт14:15–15:50Лаб.ЛР №5. INSERT, SELECT, WHERE
30.09Ср12:30–14:05Лаб.ЛР №6. UPDATE, DELETE, ORDER BY
Неделя 5 · 5–11 октября 2026
ДатаДеньВремяТипТемаОткрыть
06.10Вт12:30–14:05ЛекцияЛ.5. Транзакции. Свойства ACID
06.10Вт14:15–15:50Лаб.ЛР №7. Агрегатные функции
06.10Вт16:00–17:35Лаб.ЛР №8. GROUP BY, HAVING, ROLLUP
Неделя 6 · 12–18 октября 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
13.10Вт12:30–14:05ЛекцияЛ.6. Аномалии параллельного доступа
13.10Вт14:15–15:50Лаб.ЛР №9. Вложенные подзапросы
14.10Ср12:30–14:05Лаб.ЛР №10. Коррелированные подзапросы и EXISTS
Неделя 7 · 19–25 октября 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
20.10Вт12:30–14:05ЛекцияЛ.7. Уровни изоляции транзакций
20.10Вт14:15–15:50Лаб.ЛР №11. INNER и OUTER JOIN
21.10Ср12:30–14:05Лаб.ЛР №12. UNION, EXCEPT, INTERSECT
Неделя 8 · 26 октября – 1 ноября 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
27.10Вт12:30–14:05ЛекцияЛ.8. Блокировки, тупики, репликация
27.10Вт14:15–15:50Лаб.ЛР №13. Функции строк, чисел, дат
28.10Ср12:30–14:05Лаб.ЛР №14. CASE, ISNULL, COALESCE
Неделя 9 · 2–8 ноября 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
03.11Вт12:30–14:05ЛекцияЛ.9. Структурированные и неструктурированные данные
03.11Вт14:15–15:50Лаб.ЛР №15. Переменные и IF
04.11Ср12:30–14:05Лаб.ЛР №16. Циклы WHILE и TRY/CATCH
04.11 — День народного единства
Неделя 10 · 9–15 ноября 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
10.11Вт12:30–14:05ЛекцияЛ.10. Язык XML
10.11Вт14:15–15:50Лаб.ЛР №17. XML в SQL Server
11.11Ср12:30–14:05Лаб.ЛР №18. Иерархические данные
Неделя 11 · 16–22 ноября 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
17.11Вт12:30–14:05ЛекцияЛ.11. Администрирование и мониторинг СУБД
17.11Вт14:15–15:50Лаб.ЛР №19. MongoDB — документная БД
18.11Ср12:30–14:05Лаб.ЛР №20. Представления VIEW
Неделя 12 · 23–29 ноября 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
24.11Вт12:30–14:05ЛекцияЛ.12. Программирование в БД: процедуры, триггеры
24.11Вт14:15–15:50Лаб.ЛР №21. Хранимые процедуры
01.12Вт12:30–14:05Лаб.ЛР №22. Триггеры DML и INSTEAD OF
Неделя 13 · 30 ноября – 6 декабря 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
01.12Вт14:15–15:50ЛекцияЛ.13. Резервное копирование
02.12Ср12:30–14:05Лаб.ЛР №23. GRANT, REVOKE, роли
Неделя 14 · 7–13 декабря 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
08.12Вт12:30–14:05ЛекцияЛ.14. Восстановление данных и защита
08.12Вт14:15–15:50Лаб.ЛР №24. Восстановление данных и итоговый практикум
Неделя 15 · 14–20 декабря 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
15.12Вт12:30–14:05ЛекцияЛ.15. Распределённые БД и двухфазная фиксация
Неделя 16 · 21–27 декабря 2026 прогноз
ДатаДеньВремяТипТемаОткрыть
15.12Вт14:15–15:50ЛекцияЛ.16. Хранилища данных и подготовка к экзамену

Лекция 1. Основные понятия баз данных и СУБД

Отчёт: скриншоты + скрипт lab01_FIO.sql (ФИО латиницей).

Цель: впервые открыть SQL Server Management Studio (SSMS), подключиться к серверу в классе, разобраться с системными и пользовательскими базами, создать UniversityDB.

0. Перед началом

  1. Запустите SQL Server Management Studio из меню Пуск (можно набрать в поиске «SSMS»).
Запуск SQL Server Management Studio из меню Пуск

SQL Server Management Studio (SSMS) в меню Пуск — Microsoft SQL Server Tools.

1. Подключение к серверу

  1. В окне Connect to Server: Server type = Database Engine.
  2. Server name — как указал преподаватель (примеры: (local), .\SQLEXPRESS, ИМЯ-ПК\SQLEXPRESS).
  3. Authentication — Windows или SQL Server Authentication (логин/пароль выдаёт преподаватель).
  4. Нажмите Connect. Если ошибка — не «переустанавливайте», а поднимите руку.
Connect to Server в SSMS

Рисунок 1. Окно Connect to Server в SSMS.

2. Обзор Object Explorer

  1. Слева найдите узел Databases.
  2. Разверните System Databases. Запишите в отчёт, что видите: master, model, msdb, tempdb.
  3. Своими словами (2–3 предложения): зачем нужны master и tempdb.
  4. Посмотрите список обычных (пользовательских) баз — есть ли уже UniversityDB или базы других групп.
Системные базы данных в SSMS

Рисунок 2. Узел System Databases в Object Explorer (скриншот SSMS).

Системные базы и чужие учебные базы не удаляйте без разрешения преподавателя.

3. Создание UniversityDB

Если база UniversityDB уже есть от прошлой попытки — согласуйте с преподавателем: использовать её или создать UniversityDB_Фамилия.

  1. Способ А: правый клик Databases, New Database…, имя UniversityDB, OK.
  2. Способ Б: New Query, выполнить:
CREATE DATABASE UniversityDB;
  1. Обновите список баз (F5). Убедитесь, что UniversityDB появилась.
  2. Правый клик на UniversityDB — Properties — вкладка Files: запишите путь к файлам .mdf и .ldf.
Создание базы данных в SSMS

Создание базы: New Database… или CREATE DATABASE.

Свойства базы данных

Рисунок 3. Свойства базы — путь к файлам .mdf и .ldf (вкладка Files).

4. Первые запросы

  1. New Query. В выпадающем списке баз выберите UniversityDB.
  2. Выполните и сохраните результат в отчёт:
SELECT DB_NAME() AS current_database; SELECT @@VERSION AS sql_server_version;
  1. Ответьте: SQL Server Management Studio (SSMS) — это СУБД или клиент? Где физически лежат данные вашей базы — в SQL Server Management Studio (SSMS) или на диске сервера?
  2. Сохраните все команды в файл lab01_FIO.sql (ФИО латиницей).

На всех лабораторных имя файла: labNN_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab01_IvanovII.sql.

Окно запроса T-SQL

Окно New Query, выбор базы, команды SELECT.

Результат выполнения запроса

Рисунок 4. Результат выполнения запроса в панели Results.

5. Контрольные вопросы

  1. Что произойдёт, если закрыть SQL Server Management Studio (SSMS) без сохранения файла lab01_FIO.sql (ФИО латиницей), но после CREATE DATABASE?

Лабораторная работа №2. Таблицы и первый SELECT

Отчёт: скрипт lab02_FIO.sql (ФИО латиницей) + скриншоты результатов запросов.

Цель: в уже созданной на ЛР №1 пустой базе UniversityDB создать таблицы учебного эталона, загрузить данные и выполнить первые запросы SELECT.

0. Перед началом

  1. Запустите SSMS и подключитесь к серверу (как на ЛР №1).
  2. В Object Explorer откройте UniversityDB → Tables. Список пользовательских таблиц должен быть пуст (или только системные).
  3. New Query, в списке баз выберите UniversityDB, выполните:
USE UniversityDB; SELECT DB_NAME() AS current_database;

Если базы нет — вернитесь к ЛР №1 или выполните CREATE DATABASE UniversityDB;.

1. Где взять команды SQL

Готовые команды CREATE TABLE и INSERT — на странице Приложение: БД и скрипты, раздел «Сборка базы по шагам». Там же объяснено, что такое SQL-скрипт и зачем он разбит на блоки.

На этой лабораторной вы не скачиваете файл — копируете блоки в окно запроса и сохраняете свою версию как lab02_FIO.sql (ФИО латиницей).

Блок в приложенииНужен на ЛР №2?Что делает
1. База данныхчастичноДостаточно USE UniversityDB; — база уже есть
2. Очистка таблицнет*Только если таблицы уже создавали и нужно начать заново
3. UNIVERSITY, SUBJECTдаСправочники без внешних ключей — создаются первыми
4. STUDENT, LECTURERдаСтроки ссылаются на вуз через UNIVERSITY_ID
5. EXAM_MARKS, SUBJ_LECT, ORG_UNITдаОценки и связи; на FK ссылаются на таблицы из блоков 3–4
6. INSERTдаЭталонные данные — порядок 6.1 → 6.7, как в приложении

* Если на прошлой попытке таблицы уже есть — выполните блок 2, затем блоки 3–6 заново.

2. Создание таблиц (блоки 3–5)

  1. Откройте New Query, убедитесь, что выбрана UniversityDB.
  2. Скопируйте из приложения блок 3 (UNIVERSITY и SUBJECT), выполните F5. Должно быть сообщение об успешном создании.
  3. То же с блоком 4 (STUDENT, LECTURER) и блоком 5 (EXAM_MARKS, SUBJ_LECT, ORG_UNIT).
  4. Обновите Object Explorer (F5). Под UniversityDB → Tables должны появиться семь таблиц.
  5. Проверьте: правый клик на dbo.STUDENT → Design — видны столбцы STUDENT_ID, UNIVERSITY_ID, значок ключа у PK и FK.
Если CREATE TABLE завершился ошибкой «foreign key» — вы, скорее всего, перепутали порядок блоков. Сначала родитель (UNIVERSITY), потом дочерние таблицы.

3. Загрузка данных (блок 6)

Вставляйте блоки 6.1 → 6.7 по порядку из приложения (сначала вузы и предметы, в конце — подразделения). Можно выполнить весь блок 6 целиком или по частям — главное не нарушать порядок таблиц.

Контрольная проверка:

SELECT COUNT(*) AS student_count FROM dbo.STUDENT; SELECT COUNT(*) AS university_count FROM dbo.UNIVERSITY;

В ответе должно быть 19 студентов и 8 вузов. Сохраните скриншот результата для отчёта.

4. Первые запросы SELECT

SELECT читает данные из таблиц; он ничего не меняет. Выполните запросы ниже по очереди, результаты — в отчёт.

4.1. Все столбцы справочника вузов

Звёздочка * означает «все столбцы строки»:

SELECT * FROM dbo.UNIVERSITY;

В результате — 8 строк, столбцы UNIVERSITY_ID, UNIVERSITY_NAME, RATING, CITY.

4.2. Только название и город

Список столбцов через запятую — это проекция (выбор нужных полей):

SELECT UNIVERSITY_NAME, CITY FROM dbo.UNIVERSITY;

4.3. Студенты одного вуза

Условие WHERE отбирает строки. Номер 10 — это ВГУ в эталонных данных:

SELECT NAME, SURNAME, KURS FROM dbo.STUDENT WHERE UNIVERSITY_ID = 10 ORDER BY SURNAME;

В списке столбцов сначала NAME (имя), затем SURNAME (фамилия) — как требуется в задании.

4.4. Сколько строк в таблице

SELECT COUNT(*) AS cnt FROM dbo.STUDENT;

Агрегатная функция COUNT(*) считает строки. Для эталона ответ снова 19.

Окно запроса T-SQL

Окно New Query: сверху выбрана база UniversityDB, ниже — текст SQL.

Результат выполнения запроса

Результат SELECT — на вкладке Results.

5. Файл отчёта

  1. Сохраните в один файл lab02_FIO.sql (ФИО латиницей): команды USE, все CREATE TABLE, все INSERT и все SELECT из этой работы.
  2. Добавьте в начало файла комментарий: -- ЛР №2, IvanovII, группа ВО-ИСИТ-31 (подставьте свои фамилию и инициалы латиницей).
  3. К отчёту приложите скриншоты: список таблиц в Object Explorer, результат COUNT(*), один из запросов из §4.

6. Дополнительно

  1. Найдите в блоках 3–5 ограничения CHECK (стипендия ≥ 0, курс 1–6, оценка 2–5). Выполните заведомо неверный INSERT, например студента с KURS = 9, и прочитайте текст ошибки.
  2. Попробуйте вставить студента с UNIVERSITY_ID = 999. СУБД должна отклонить строку — нет такого вуза, сработал внешний ключ.
  3. Откройте dbo.EXAM_MARKS и найдите студента без оценок (STUDENT_ID = 19). Эта строка специально нужна для заданий с IS NULL на следующих лабораторных.

Контрольные вопросы

  1. Чем пустая UniversityDB после ЛР №1 отличается от той же базы после этой работы?
  2. Почему таблицу UNIVERSITY создают раньше, чем STUDENT?
  3. Что делает SELECT * FROM UNIVERSITY и чем он отличается от SELECT UNIVERSITY_NAME, CITY FROM UNIVERSITY?
  4. Что произойдёт при INSERT студента с несуществующим UNIVERSITY_ID?
  5. Зачем в отчёте хранить файл lab02_FIO.sql (ФИО латиницей), если база уже создана на сервере?

Лабораторная работа №3. DDL: CREATE, типы, ограничения

Отчёт: скрипт lab03_FIO.sql (ФИО латиницей) + скриншоты ошибок ограничений.

Цель: в той же UniversityDB, что и на ЛР №2, добавить нормализованные таблицы (группы и учебная библиотека вуза) с ограничениями PRIMARY KEY, UNIQUE, CHECK, FOREIGN KEY, загрузить данные и убедиться, что СУБД отклоняет неверные строки.

Связь с лекцией 3: декомпозиция «широкой» таблицы на сущности — как UNIVERSITY + STUDENT на ЛР №2 и как LIB_AUTHOR → LIB_BOOK → LIB_COPY сегодня. Отдельную базу данных на курсе не создаём.

0. Перед началом

  1. Запустите SSMS и подключитесь к серверу.
  2. Должна существовать UniversityDB после ЛР №2 (семь таблиц: UNIVERSITY, STUDENT, …).
  3. Откройте New Query, выберите базу UniversityDB. Весь SQL ниже выполняйте только в ней.
Не выполняйте DROP DATABASE UniversityDB и не пересоздавайте таблицы ЛР №2 — только CREATE TABLE для новых имён ниже. Если ЛР №3 уже сдавалась, перед повтором удалите свои таблицы: DROP TABLE для LIB_COPY, LIB_BOOK, LIB_AUTHOR, ACADEMIC_GROUP (в таком порядке).

1. Рабочая база курса

На ЛР №1 вы создавали контейнер базы; сегодня дополняем уже существующую схему — так устроен весь курс: одна UniversityDB от CREATE TABLE до курсовой.

USE UniversityDB; GO SELECT DB_NAME() AS current_database; SELECT COUNT(*) AS table_cnt FROM sys.tables WHERE schema_id = SCHEMA_ID(N'dbo');

В current_database должно быть UniversityDB. Число таблиц до работы — обычно 7 (после шага 2 станет 11).

2. Новые таблицы (лекция 3, пример Б + библиотека вуза)

Сначала справочник групп (староста хранится один раз — см. лекцию 3 §4.3), затем цепочка библиотеки: автор → книга → экземпляр. Создавайте таблицы в указанном порядке.

ТаблицаНазначениеКлючевые ограничения
ACADEMIC_GROUPУчебные группыGROUP_ID — PK; код группы; фамилия старосты
LIB_AUTHORАвторы учебников/худ. лит.AUTHOR_ID — PK
LIB_BOOKКниги (издания)BOOK_ID — PK; ISBN — UNIQUE; PUB_YEAR — CHECK; FK на автора
LIB_COPYЭкземпляры в библиотеке вузаCOPY_ID — PK; инв. номер — UNIQUE; STATUS — CHECK; FK на книгу + CASCADE

2.1. ACADEMIC_GROUP

CREATE TABLE dbo.ACADEMIC_GROUP ( GROUP_ID INT NOT NULL CONSTRAINT PK_ACADEMIC_GROUP PRIMARY KEY, GROUP_CODE NVARCHAR(20) NOT NULL, MONITOR_SURNAME NVARCHAR(80) NOT NULL );

2.2. LIB_AUTHOR

CREATE TABLE dbo.LIB_AUTHOR ( AUTHOR_ID INT NOT NULL CONSTRAINT PK_LIB_AUTHOR PRIMARY KEY, SURNAME NVARCHAR(100) NOT NULL, NAME NVARCHAR(100) NOT NULL );

2.3. LIB_BOOK

CREATE TABLE dbo.LIB_BOOK ( BOOK_ID INT NOT NULL CONSTRAINT PK_LIB_BOOK PRIMARY KEY, ISBN CHAR(13) NOT NULL UNIQUE, TITLE NVARCHAR(200) NOT NULL, PUB_YEAR INT NOT NULL, AUTHOR_ID INT NOT NULL, CONSTRAINT CK_LIB_BOOK_YEAR CHECK (PUB_YEAR BETWEEN 1500 AND YEAR(GETDATE())), CONSTRAINT FK_LIB_BOOK_AUTHOR FOREIGN KEY (AUTHOR_ID) REFERENCES dbo.LIB_AUTHOR(AUTHOR_ID) );

PUB_YEAR — год издания; CHECK не допускает «1300» и будущие годы.

2.4. LIB_COPY

CREATE TABLE dbo.LIB_COPY ( COPY_ID INT NOT NULL CONSTRAINT PK_LIB_COPY PRIMARY KEY, BOOK_ID INT NOT NULL, INVENTORY_NO VARCHAR(20) NOT NULL UNIQUE, STATUS CHAR(3) NOT NULL CONSTRAINT DF_LIB_COPY_STATUS DEFAULT ('in'), CONSTRAINT CK_LIB_COPY_STATUS CHECK (STATUS IN ('in', 'out')), CONSTRAINT FK_LIB_COPY_BOOK FOREIGN KEY (BOOK_ID) REFERENCES dbo.LIB_BOOK(BOOK_ID) ON DELETE CASCADE );

ON DELETE CASCADE: при удалении книги СУБД удалит все её экземпляры. STATUS: in — на полке, out — выдан читателю.

Object Explorer (F5): под UniversityDB → Tables — четыре новые таблицы рядом с STUDENT, EXAM_MARKS и др.

3. Загрузка данных

Сначала группы и авторы, затем книги, затем экземпляры — как при загрузке UniversityDB на ЛР №2.

INSERT INTO dbo.ACADEMIC_GROUP (GROUP_ID, GROUP_CODE, MONITOR_SURNAME) VALUES (31, N'ВО-ИСИТ-31', N'Петрова'), (32, N'ВО-ИСИТ-32', N'Сидоров'); INSERT INTO dbo.LIB_AUTHOR (AUTHOR_ID, SURNAME, NAME) VALUES (1, N'Пушкин', N'Александр'), (2, N'Толстой', N'Лев'), (3, N'Достоевский', N'Фёдор'); INSERT INTO dbo.LIB_BOOK (BOOK_ID, ISBN, TITLE, PUB_YEAR, AUTHOR_ID) VALUES (10, '9785170901234', N'Евгений Онегин', 1833, 1), (11, '9785170905678', N'Война и мир', 1869, 2), (12, '9785170909012', N'Преступление и наказание', 1866, 3); INSERT INTO dbo.LIB_COPY (COPY_ID, BOOK_ID, INVENTORY_NO, STATUS) VALUES (100, 10, 'INV-001', 'in'), (101, 10, 'INV-002', 'out'), (102, 11, 'INV-003', 'in'), (103, 12, 'INV-004', 'in');

Можете добавить свои строки (минимум 3–5 в каждой таблице). Проверка:

SELECT COUNT(*) AS group_cnt FROM dbo.ACADEMIC_GROUP; SELECT COUNT(*) AS author_cnt FROM dbo.LIB_AUTHOR; SELECT COUNT(*) AS book_cnt FROM dbo.LIB_BOOK; SELECT COUNT(*) AS copy_cnt FROM dbo.LIB_COPY;

4. Проверка ограничений

Выполните команды ниже по одной. Каждая должна завершиться ошибкой — это ожидаемый результат. Сохраните текст ошибки или скриншот для отчёта.

4.1. Дубликат ISBN

INSERT INTO dbo.LIB_BOOK (BOOK_ID, ISBN, TITLE, PUB_YEAR, AUTHOR_ID) VALUES (99, '9785170901234', N'Дубликат', 2000, 1);

Нарушение UNIQUE на ISBN.

4.2. Недопустимый год

INSERT INTO dbo.LIB_BOOK (BOOK_ID, ISBN, TITLE, PUB_YEAR, AUTHOR_ID) VALUES (98, '9785170999999', N'Старое издание', 1300, 1);

Нарушение CHECK на PUB_YEAR.

4.3. Недопустимый статус

INSERT INTO dbo.LIB_COPY (COPY_ID, BOOK_ID, INVENTORY_NO, STATUS) VALUES (199, 10, 'INV-BAD', 'broken');

Нарушение CHECK на STATUS — допустимы только in и out.

4.4. Дополнительно (по желанию)

INSERT INTO dbo.LIB_BOOK (BOOK_ID, ISBN, TITLE, PUB_YEAR, AUTHOR_ID) VALUES (97, '9785170888888', N'Без автора', 2020, 999);

Нарушение внешнего ключа — автора с AUTHOR_ID = 999 нет.

5. Нормальные формы (письменный ответ в отчёте)

Кратко ответьте в комментарии в lab03_FIO.sql или в сопроводительном тексте:

  1. Выполняется ли 1НФ? (атомарные ячейки, нет «списков авторов» в одной строке книги)
  2. Выполняется ли 3НФ? (фамилия автора в LIB_AUTHOR, а не в каждой строке LIB_COPY; староста в ACADEMIC_GROUP, а не в каждой «широкой» строке с оценкой)
  3. Что было бы плохого в одной таблице «всё сразу»: автор + ISBN + инвентарный номер + статус?

Ожидаемый вывод: схема в 1НФ и 3НФ; разделение убирает аномалии обновления (смена фамилии автора — одна строка в LIB_AUTHOR).

6. Файл отчёта

  1. Сохраните в один файл lab03_FIO.sql (ФИО латиницей): USE UniversityDB, все CREATE TABLE, все успешные INSERT, контрольные SELECT COUNT.
  2. Неверные INSERT из §4 можно оставить в файле закомментированными (-- в начале строки) с пометкой «ожидаемая ошибка».
  3. В начале файла: -- ЛР №3, IvanovII, группа ВО-ИСИТ-31.
  4. К отчёту приложите скриншоты: список таблиц в Object Explorer, одна успешная вставка, одна ошибка CHECK или UNIQUE.

Контрольные вопросы

  1. Почему по курсу все лабораторные (включая эту) расширяют одну UniversityDB, а не создают новую базу на каждую тему?
  2. Почему LIB_BOOK создают после LIB_AUTHOR, а LIB_COPY — после LIB_BOOK?
  3. Чем PRIMARY KEY отличается от UNIQUE на примере ISBN и BOOK_ID?
  4. Что делает ON DELETE CASCADE при удалении строки из LIB_BOOK?
  5. Какая аномалия обновления исчезает, когда фамилия автора хранится только в LIB_AUTHOR?

Лабораторная работа №4. FK, ALTER TABLE, GO

Отчёт: скрипт lab04_FIO.sql (ФИО латиницей) + скриншоты из §1–5.

Цель: изменить существующую схему UniversityDB командами ALTER TABLE, добавить индексы, поработать с пакетами GO и убедиться, что ограничения FK и UNIQUE работают.

Связь с лекцией 4: схема живёт на общем сервере; ваш ALTER TABLE видят все сеансы. Внешние ключи с ЛР №2 защищают ссылки; сегодня добавляете столбец и индексы без пересоздания таблиц.

0. Перед началом

  1. Запустите SSMS, подключитесь к учебному серверу (как на ЛР №1).
  2. В Object Explorer откройте UniversityDB → Tables — как минимум семь таблиц после ЛР №2 (после ЛР №3 — ещё ACADEMIC_GROUP и LIB_*).
  3. New Query, в списке баз выберите UniversityDB, выполните контроль:
USE UniversityDB; SELECT COUNT(*) AS student_cnt FROM dbo.STUDENT; SELECT COUNT(*) AS mark_cnt FROM dbo.EXAM_MARKS;

Ожидается: 19 студентов и непустая таблица оценок. Если база пуста — повторите ЛР №2 (блоки приложения 3–6).

Не выполняйте DROP DATABASE и не трогайте чужие базы на общем сервере.
Object Explorer — таблицы UniversityDB

Object Explorer: под UniversityDB → Tables — STUDENT, UNIVERSITY, …

1. ALTER TABLE — новый столбец EMAIL

На ЛР №2 таблицы создавали через CREATE TABLE. В живой системе схему чаще дополняют — так деканат добавляет поле «email» без пересоздания таблицы и без потери 19 строк.

ALTER TABLE dbo.STUDENT ADD EMAIL VARCHAR(100) NULL;
  1. Выполните команду (F5). Сообщение: Commands completed successfully.
  2. Обновите Object Explorer (F5). Правый клик dbo.STUDENT → Design — в списке столбцов появился EMAIL, тип varchar(100), Allow Nulls = да.
  3. Заполните адреса по шаблону student<STUDENT_ID>@edu.local:
UPDATE dbo.STUDENT SET EMAIL = 'student' + CAST(STUDENT_ID AS VARCHAR(10)) + '@edu.local' WHERE EMAIL IS NULL;

Конкретный запрос SELECT и ожидаемый фрагмент результата:

SELECT TOP 5 STUDENT_ID, SURNAME, EMAIL FROM dbo.STUDENT ORDER BY STUDENT_ID;
STUDENT_IDSURNAMEEMAIL
1…student1@edu.local
2…student2@edu.local
………

Фамилии возьмутся из вашего эталона; важны столбец EMAIL и шаблон адреса. Сделайте скриншот вкладки Results.

Окно запроса ALTER и UPDATE

Окно New Query: сверху выбрана UniversityDB, ниже — ALTER и UPDATE.

Результат SELECT с EMAIL

Результат SELECT TOP 5 … EMAIL — приложите к отчёту.

2. Ограничение UNIQUE на EMAIL

UNIQUE запрещает два одинаковых значения в столбце (кроме NULL — в SQL Server несколько NULL в UNIQUE допустимы, но у вас все EMAIL заполнены).

ALTER TABLE dbo.STUDENT ADD CONSTRAINT UQ_STUDENT_EMAIL UNIQUE (EMAIL);

Теперь намеренно нарушите правило — скопируйте адрес студента 1 студенту 2:

UPDATE dbo.STUDENT SET EMAIL = 'student1@edu.local' WHERE STUDENT_ID = 2;

Ожидаемо: выполнение прервётся, на вкладке Messages текст вроде:

Msg 2627, Level 14, State 1 Violation of UNIQUE KEY constraint 'UQ_STUDENT_EMAIL'. Cannot insert duplicate key …

Сохраните скриншот вкладки Messages — это доказательство работы ограничения. Верните уникальные значения:

UPDATE dbo.STUDENT SET EMAIL = 'student' + CAST(STUDENT_ID AS VARCHAR(10)) + '@edu.local';

2.1. Напоминание про FK (с ЛР №2)

Если бы вы добавляли столбец UNIVERSITY_ID вместо EMAIL, FK не дал бы записать несуществующий вуз. Проверка (ожидается ошибка):

-- ожидаемая ошибка FK — выполните и прочитайте Messages: UPDATE dbo.STUDENT SET UNIVERSITY_ID = 999 WHERE STUDENT_ID = 1;

3. Индексы для ускорения поиска

Индекс — отдельная структура для быстрого поиска по столбцу. На ЛР №5–6 вы часто будете писать WHERE CITY = … и WHERE UNIVERSITY_ID = … AND KURS = … — под такие фильтры индексы уместны.

CREATE NONCLUSTERED INDEX IX_STUDENT_CITY ON dbo.STUDENT (CITY); CREATE NONCLUSTERED INDEX IX_STUDENT_UNIV_KURS ON dbo.STUDENT (UNIVERSITY_ID, KURS);

Clustered индекс один на таблицу (обычно PK); nonclustered — дополнительные «указатели» к строкам.

4. Просмотр индексов через sys.indexes

SELECT t.name AS table_name, i.name AS index_name, i.type_desc, i.is_unique FROM sys.indexes i JOIN sys.tables t ON i.object_id = t.object_id WHERE t.name = N'STUDENT' AND i.name IS NOT NULL ORDER BY i.index_id;

В результате должны быть как минимум:

index_nametype_descis_uniqueКомментарий
PK__STUDENT…CLUSTERED1первичный ключ
UQ_STUDENT_EMAILNONCLUSTERED1ваше UNIQUE
IX_STUDENT_CITYNONCLUSTERED0создали в §3
IX_STUDENT_UNIV_KURSNONCLUSTERED0составной индекс

Точное имя PK может отличаться — смотрите столбец index_name.

5. Пакеты GO

GO — не команда T-SQL, а разделитель пакетов в SSMS. Переменная, объявленная в одном пакете, не видна в следующем.

DECLARE @db SYSNAME = DB_NAME(); SELECT @db AS current_db; GO DECLARE @cnt INT; SELECT @cnt = COUNT(*) FROM dbo.STUDENT; SELECT @cnt AS students; GO

Ожидаемый результат второго пакета: students = 19.

Эксперимент: уберите оба GO и выполните скрипт целиком. Вторая строка DECLARE @cnt в том же пакете даст ошибку «имя переменной уже объявлено» или конфликт с первым пакетом — зафиксируйте текст ошибки в отчёте.

Если видите Cannot find object STUDENT — выполните USE UniversityDB;. Если столбец EMAIL уже добавлен — пропустите §1 или согласуйтесь с преподавателем. Повторный CREATE INDEX даст ошибку — индекс уже есть.

6. Файл отчёта

  1. Сохраните в один файл lab04_FIO.sql (ФИО латиницей): USE, все ALTER, UPDATE, CREATE INDEX, SELECT из sys.indexes, скрипт с GO.
  2. В начале: -- ЛР №4, IvanovII, группа ВО-ИСИТ-31 (подставьте свои фамилию и инициалы латиницей).
  3. К отчёту приложите скриншоты: Object Explorer с таблицами; результат §1; ошибка UNIQUE §2; список индексов §4.
  4. Согласуйте с преподавателем: оставить EMAIL и индексы для ЛР №5+ или удалить в конце скрипта:
-- по договорённости — откат схемы: -- ALTER TABLE dbo.STUDENT DROP CONSTRAINT UQ_STUDENT_EMAIL; -- DROP INDEX IX_STUDENT_CITY ON dbo.STUDENT; -- DROP INDEX IX_STUDENT_UNIV_KURS ON dbo.STUDENT; -- ALTER TABLE dbo.STUDENT DROP COLUMN EMAIL;

Имя файла отчёта: lab04_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab04_IvanovII.sql.

7. Дополнительно (если осталось время)

  1. Выполните EXEC sp_helpindex 'dbo.STUDENT'; — сравните вывод с sys.indexes.
  2. Добавьте индекс только если его ещё нет — обсудите, зачем в production проверяют IF NOT EXISTS (на курсе достаточно комментария).
  3. Объясните соседу, чем ALTER TABLE ADD безопаснее, чем «удалить STUDENT и создать заново».

Контрольные вопросы

  1. Зачем на ЛР №2 создавали FK на родительские таблицы раньше дочерних?
  2. Чем ALTER TABLE ADD отличается от повторного CREATE TABLE STUDENT?
  3. Почему UNIQUE на EMAIL отклонил второй одинаковый адрес?
  4. Зачем в одном скрипте несколько пакетов GO?
  5. Как по sys.indexes отличить clustered и nonclustered индекс?

Лабораторная работа №5. INSERT, SELECT, WHERE

Отчёт: скрипт lab05_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: выполнить выборку с проекцией (список столбцов) и селекцией (WHERE): сравнение, AND/OR/NOT, IN, BETWEEN, LIKE, IS NULL на UniversityDB.

Связь с лекцией 2: вы уже делали простые SELECT на ЛР №2; здесь — систематическая работа с фильтрами. Справочник таблиц и эталонные данные — в приложении.

0. Перед началом

  1. SSMS → подключение к учебному серверу → база UniversityDB.
  2. Если на ЛР №4 добавляли столбец EMAIL — он не мешает; все запросы ниже работают и без него.
  3. Контроль эталона:
USE UniversityDB; SELECT COUNT(*) AS students FROM dbo.STUDENT; SELECT COUNT(*) AS marks FROM dbo.EXAM_MARKS; SELECT COUNT(*) AS subjects FROM dbo.SUBJECT;

Ожидается: 19 студентов, 24 строки в EXAM_MARKS, 8 предметов в SUBJECT (см. приложение).

Окно запроса SELECT

Перед работой убедитесь, что в списке баз выбрана UniversityDB.

1. Проекция — выбор столбцов

Проекция — какие столбцы показать. Селекция — какие строки отобрать (WHERE, §2–4).

1.1. Все предметы

SELECT * FROM dbo.SUBJECT;

Ожидается 8 строк, столбцы SUBJ_ID, SUBJ_NAME, HOUR, SEMESTER.

1.2. Оценки по предмету «Информатика» (SUBJ_ID = 10)

SELECT STUDENT_ID, SUBJ_ID, MARK, EXAM_DATE FROM dbo.EXAM_MARKS WHERE SUBJ_ID = 10 ORDER BY STUDENT_ID;

В эталоне — несколько строк (оценки разных студентов). В комментарии к скрипту укажите -- rows: N.

1.3. Список студентов — только нужные поля

SELECT STUDENT_ID, SURNAME, NAME, KURS, UNIVERSITY_ID, STIPEND, CITY FROM dbo.STUDENT ORDER BY SURNAME;

Ожидается 19 строк. Звёздочка * здесь не нужна — вы явно перечисляете столбцы отчёта.

2. Простые фильтры WHERE

Выполняйте запросы по одному. После каждого — запишите число строк (rows в углу Results или SELECT COUNT(*) … с тем же WHERE).

2.1. Предметы 4-го семестра

SELECT SUBJ_ID, SUBJ_NAME, SEMESTER, HOUR FROM dbo.SUBJECT WHERE SEMESTER = 4;

Ожидается 1 строка — «История» (SUBJ_ID = 56).

2.2. Студенты 3 курса и старше

SELECT SURNAME, NAME, KURS FROM dbo.STUDENT WHERE KURS >= 3 ORDER BY KURS, SURNAME;

2.3. Стипендия больше 140

SELECT SURNAME, STIPEND FROM dbo.STUDENT WHERE STIPEND > 140 ORDER BY STIPEND DESC;

2.4. Предметы длиннее 40 академических часов

SELECT SUBJ_NAME, HOUR FROM dbo.SUBJECT WHERE HOUR > 40 ORDER BY HOUR DESC;

Ожидается 4 строки (56, 72, 56, 56 часов в эталоне).

2.5. Вузы с рейтингом выше 400

SELECT UNIVERSITY_NAME, RATING, CITY FROM dbo.UNIVERSITY WHERE RATING > 400 ORDER BY RATING DESC;

Ожидается 6 вузов (рейтинг 410, 450, 470, 580, 650, 700).

Результат SELECT с WHERE

Пример результата с фильтром — приложите один такой скриншот к отчёту.

3. Сложные условия — AND, OR, IN, BETWEEN

3.1. Студенты из Воронежа со стипендией

SELECT SURNAME, CITY, STIPEND FROM dbo.STUDENT WHERE CITY = N'Воронеж' AND STIPEND > 0 ORDER BY STIPEND DESC;

Буква N перед строкой — Unicode для кириллицы.

3.2. Преподаватели из Воронежа

SELECT LECTURER_ID, SURNAME, NAME, CITY FROM dbo.LECTURER WHERE CITY = N'Воронеж';

3.3. Скобки и OR

SELECT SURNAME, KURS, STIPEND FROM dbo.STUDENT WHERE (KURS = 1 OR KURS = 2) AND STIPEND >= 100 ORDER BY KURS, SURNAME;

Без скобок AND связывал бы только KURS = 2 со стипендией — логика изменилась бы.

3.4. IN и BETWEEN

SELECT SURNAME, KURS FROM dbo.STUDENT WHERE KURS IN (2, 4, 5); SELECT SURNAME, STIPEND FROM dbo.STUDENT WHERE STIPEND BETWEEN 100 AND 180;

4. LIKE и IS NULL

4.1. Фамилии на «С»

SELECT SURNAME, NAME FROM dbo.STUDENT WHERE SURNAME LIKE N'С%' ORDER BY SURNAME;

% — любое продолжение. Укажите в комментарии, сколько строк вернулось.

4.2. Студенты без города

SELECT STUDENT_ID, SURNAME, NAME, CITY FROM dbo.STUDENT WHERE CITY IS NULL;

Ожидается 1 строка — STUDENT_ID = 19 (специально для этой проверки).

4.3. Ошибка: = NULL

-- НЕПРАВИЛЬНО — вернёт 0 строк: SELECT STUDENT_ID FROM dbo.STUDENT WHERE CITY = NULL; -- ПРАВИЛЬНО: SELECT STUDENT_ID FROM dbo.STUDENT WHERE CITY IS NULL;

Сохраните скриншот: сравнение «0 строк» и «1 строка» — хороший фрагмент отчёта.

5. Частые ошибки

ОшибкаЧто проверить
0 строк там, где ждали данныеВыбрана ли UniversityDB; нет ли опечатки в N'Воронеж'
CITY = NULLТолько IS NULL / IS NOT NULL
Фильтр по SEMESTER в STUDENTСеместр — столбец таблицы SUBJECT, не студента
Забыли dbo.На учебном сервере лучше явно: dbo.STUDENT

6. Файл отчёта

  1. Сохраните все запросы из §1–4 в один файл lab05_FIO.sql (ФИО латиницей).
  2. В начале файла: -- ЛР №5, IvanovII, группа ВО-ИСИТ-31 (подставьте свои фамилию и инициалы латиницей).
  3. К каждому блоку §2–4 добавьте комментарий -- rows: N с числом строк результата.
  4. К отчёту приложите скриншоты: контроль §0; один запрос из §2; сравнение = NULL и IS NULL из §4.3.

Имя файла отчёта: lab05_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab05_IvanovII.sql.

7. Дополнительно (если осталось время)

  1. SELECT * FROM dbo.STUDENT WHERE NOT (KURS < 3); — сравните с KURS >= 3.
  2. Запрос: студенты вуза ВГУ (UNIVERSITY_ID = 10) с стипендией выше средней по этому вузу (подсказка: подзапрос — ЛР №9).
  3. Объясните, почему SELECT не меняет данные и не требует ROLLBACK (в отличие от ЛР №6).

Контрольные вопросы

  1. Чем проекция отличается от селекции в одном SELECT?
  2. Почему условие на SEMESTER относится к таблице SUBJECT, а не STUDENT?
  3. Что вернёт LIKE N'С%' и зачем буква N?
  4. Чем IS NULL отличается от = NULL?
  5. Зачем в отчёте хранить файл lab05_FIO.sql (ФИО латиницей), если результат виден на экране?

Лабораторная работа №6. UPDATE, DELETE, ORDER BY

Отчёт: скрипт lab06_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: изменять данные (DML), сортировать выборку, использовать TOP и DISTINCT; безопасно экспериментировать в транзакции с ROLLBACK (лекция 5).

Связь с лекцией 5–6: на общем сервере незафиксированные UPDATE/DELETE видят другие сеансы — поэтому учебные изменения только с откатом.

Все демонстрации UPDATE, INSERT и DELETE ниже выполняйте внутри BEGIN TRAN … ROLLBACK. Не нажимайте COMMIT, пока не согласовали с преподавателем.

0. Перед началом

USE UniversityDB; SELECT COUNT(*) AS student_cnt FROM dbo.STUDENT; SELECT COUNT(*) AS mark_cnt FROM dbo.EXAM_MARKS;

Ожидается 19 студентов. Запишите число оценок — после всех ROLLBACK оно должно совпасть.

1. ORDER BY, TOP, DISTINCT

ORDER BY сортирует результат; TOP n ограничивает число строк (аналог LIMIT в других СУБД). DISTINCT убирает дубликаты в выборке.

1.1. Сортировка по стипендии

SELECT SURNAME, STIPEND FROM dbo.STUDENT ORDER BY STIPEND DESC;

Вверху списка — студенты с наибольшей стипендией. Скриншот для отчёта.

1.2. TOP 5

SELECT TOP 5 SURNAME, STIPEND FROM dbo.STUDENT ORDER BY STIPEND DESC;

Ровно 5 строк (если в таблице ≥ 5 студентов).

1.3. DISTINCT

SELECT DISTINCT MARK FROM dbo.EXAM_MARKS WHERE MARK IS NOT NULL ORDER BY MARK; SELECT DISTINCT KURS, CITY FROM dbo.STUDENT ORDER BY KURS, CITY;

В первом запросе — уникальные оценки (2–5); во втором — уникальные пары «курс + город».

Результат ORDER BY и TOP

Результат TOP 5 … ORDER BY STIPEND DESC — приложите к отчёту.

2. INSERT в транзакции

Сначала «пробные» строки — затем откат. Порядок: родитель UNIVERSITY, потом дочерний STUDENT (FK).

BEGIN TRAN; INSERT INTO dbo.UNIVERSITY (UNIVERSITY_ID, UNIVERSITY_NAME, RATING, CITY) VALUES (99, N'Тестовый вуз', 100, N'Тестград'); INSERT INTO dbo.STUDENT (STUDENT_ID, NAME, SURNAME, KURS, UNIVERSITY_ID, STIPEND, CITY, BIRTHDAY) VALUES (99, N'Тест', N'Тестов', 1, 99, 0, N'Тестград', '2005-01-01'); SELECT COUNT(*) AS cnt FROM dbo.STUDENT WHERE UNIVERSITY_ID = 99; -- 1 INSERT INTO dbo.UNIVERSITY (UNIVERSITY_ID, UNIVERSITY_NAME, RATING, CITY) SELECT 98, N'Высокий рейтинг', MAX(RATING) + 10, N'Москва' FROM dbo.UNIVERSITY; ROLLBACK TRAN; SELECT COUNT(*) AS student_cnt FROM dbo.STUDENT; -- снова 19

INSERT … SELECT вставляет строку, вычисленную запросом (здесь — рейтинг выше текущего максимума).

3. UPDATE в транзакции

Перед изменением — SELECT с тем же WHERE; после UPDATE — повторный SELECT; в конце — ROLLBACK.

BEGIN TRAN; UPDATE dbo.STUDENT SET STIPEND = STIPEND * 1.10 WHERE KURS = 1; SELECT STUDENT_ID, SURNAME, STIPEND FROM dbo.STUDENT WHERE KURS = 1; UPDATE dbo.STUDENT SET UNIVERSITY_ID = 14 WHERE STUDENT_ID = 15; SELECT STUDENT_ID, SURNAME, UNIVERSITY_ID FROM dbo.STUDENT WHERE STUDENT_ID = 15; ROLLBACK TRAN; SELECT STUDENT_ID, UNIVERSITY_ID FROM dbo.STUDENT WHERE STUDENT_ID = 15;

После ROLLBACK у студента 15 снова должен быть исходный UNIVERSITY_ID из эталона.

4. DELETE с проверкой

BEGIN TRAN; SELECT COUNT(*) AS bad_marks FROM dbo.EXAM_MARKS WHERE MARK < 3; DELETE FROM dbo.EXAM_MARKS WHERE MARK < 3; SELECT COUNT(*) AS after_delete FROM dbo.EXAM_MARKS WHERE MARK < 3; ROLLBACK TRAN; SELECT COUNT(*) AS bad_marks_again FROM dbo.EXAM_MARKS WHERE MARK < 3;

После отката последний COUNT совпадает с первым — двойки (если были) на месте.

5. Удаление и внешний ключ

Нельзя удалить вуз, пока на него ссылаются студенты. Сначала проверьте ошибку:

BEGIN TRAN; INSERT INTO dbo.UNIVERSITY (UNIVERSITY_ID, UNIVERSITY_NAME, RATING, CITY) VALUES (99, N'Тест', 100, N'Тест'); INSERT INTO dbo.STUDENT (STUDENT_ID, NAME, SURNAME, KURS, UNIVERSITY_ID, STIPEND, CITY, BIRTHDAY) VALUES (99, N'Т', N'Тестов', 1, 99, 0, N'Т', '2005-01-01'); DELETE FROM dbo.UNIVERSITY WHERE UNIVERSITY_ID = 99; -- ожидается ошибка FK ROLLBACK TRAN;

Правильный порядок внутри транзакции: сначала DELETE студентов, потом вуза.

BEGIN TRAN; -- … те же INSERT … DELETE FROM dbo.STUDENT WHERE UNIVERSITY_ID = 99; DELETE FROM dbo.UNIVERSITY WHERE UNIVERSITY_ID = 99; ROLLBACK TRAN;

6. Частые ошибки

ОшибкаЧто делать
Случайный COMMITНа учебном сервере — только ROLLBACK; пересоздайте эталон с преподавателем
UPDATE без WHEREСначала SELECT с тем же условием — убедитесь, что трогаете нужные строки
DELETE родителя раньше ребёнкаСначала дочерние строки или CASCADE (если задан)
Забыли ROLLBACKSELECT @@TRANCOUNT; — если > 0, выполните ROLLBACK

7. Файл отчёта

  1. Сохраните все команды §1–5 в lab06_FIO.sql (ФИО латиницей).
  2. В начале: -- ЛР №6, IvanovII, группа ВО-ИСИТ-31.
  3. К каждому блоку с UPDATE/DELETE добавьте комментарий «до / после / после ROLLBACK».
  4. Скриншоты: TOP 5; один UPDATE до ROLLBACK и после; ошибка FK при DELETE вуза.
  5. Финальная проверка: SELECT COUNT(*) FROM dbo.STUDENT; = 19.

Имя файла отчёта: lab06_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab06_IvanovII.sql.

8. Дополнительно

  1. SELECT TOP 5 PERCENT STIPEND, … ORDER BY STIPEND DESC; — чем отличается от TOP 5?
  2. Попробуйте UPDATE с заведомо неверным CHECK (KURS = 9) внутри TRY/CATCH (ЛР №16).

Контрольные вопросы

  1. Почему ORDER BY пишут после WHERE?
  2. Зачем ROLLBACK после демонстрационного UPDATE на общем сервере?
  3. Чем INSERT … SELECT отличается от INSERT … VALUES?
  4. Почему DELETE вуза без удаления студентов вызывает ошибку FK?
  5. Какая аномалия из лекции 6 связана с незафиксированными изменениями соседа?

Лабораторная работа №7. Агрегатные функции

Отчёт: скрипт lab07_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: использовать COUNT, SUM, AVG, MIN, MAX; понять, как NULL влияет на агрегаты; сверить ответы с эталоном из приложения.

Связь с курсом: на лекции 2 вы делали простые SELECT; здесь одна строка результата суммирует много строк таблицы. На ЛР №8 добавится GROUP BY — группы вместо «всей таблицы сразу».

Напоминание: все агрегаты, кроме COUNT(*), игнорируют строки, где аргумент равен NULL.

0. Перед началом

USE UniversityDB; SELECT COUNT(*) AS student_cnt FROM dbo.STUDENT; SELECT COUNT(*) AS mark_cnt FROM dbo.EXAM_MARKS; SELECT COUNT(*) AS subject_cnt FROM dbo.SUBJECT;

Ожидается: 19 студентов, 24 оценки, 8 предметов. Если числа другие — восстановите эталон (ЛР №2, блок 6 приложения).

1. COUNT — три варианта

COUNT(*) считает строки. COUNT(столбец) не учитывает NULL в этом столбце. COUNT(DISTINCT …) — число различных значений (NULL не входит).

1.1. Студенты и города

SELECT COUNT(*) AS all_rows FROM dbo.STUDENT; SELECT COUNT(CITY) AS with_city FROM dbo.STUDENT; SELECT COUNT(DISTINCT CITY) AS distinct_cities FROM dbo.STUDENT;

Ожидается: 19, 18, 8. У студента STUDENT_ID = 19 поле CITY специально NULL — поэтому COUNT(CITY) на 1 меньше, чем COUNT(*).

В комментарии к скрипту запишите: -- all_rows: 19; with_city: 18; distinct_cities: 8.

2. MIN, MAX, AVG по стипендии

SELECT MIN(STIPEND) AS min_st, MAX(STIPEND) AS max_st, AVG(STIPEND) AS avg_st FROM dbo.STUDENT; SELECT AVG(STIPEND) AS avg_positive FROM dbo.STUDENT WHERE STIPEND > 0;

Ожидается: min_st = 0, max_st = 250, avg_st ≈ 122.89 (среднее по всем 19, включая нулевые стипендии). Во втором запросе среднее только по студентам с STIPEND > 0 — ≈ 155.67 (15 строк).

Обратите внимание: нули в данных — не NULL; они участвуют в AVG первого запроса и занижают среднее.

3. Агрегаты по предметам, вузам и оценкам

Выполняйте запросы по одному; после каждого сверяйте результат с эталоном.

3.1. Часы и рейтинги

SELECT SUM(HOUR) AS total_hours FROM dbo.SUBJECT; SELECT MIN(RATING) AS min_rating, MAX(RATING) AS max_rating FROM dbo.UNIVERSITY;

Ожидается: total_hours = 382 (сумма часов восьми предметов); min_rating = 320 (БГУ), max_rating = 700 (МГУ).

3.2. Оценки

SELECT AVG(CAST(MARK AS FLOAT)) AS avg_mark FROM dbo.EXAM_MARKS; SELECT COUNT(*) AS fives FROM dbo.EXAM_MARKS WHERE MARK = 5; SELECT COUNT(*) AS twos FROM dbo.EXAM_MARKS WHERE MARK = 2; SELECT MIN(EXAM_DATE) AS first_exam, MAX(EXAM_DATE) AS last_exam FROM dbo.EXAM_MARKS;

Ожидается: avg_mark ≈ 4.08; 9 пятёрок; 1 двойка; первая дата 2026-01-15, последняя 2026-06-12.

CAST(MARK AS FLOAT) нужен, чтобы среднее было дробным, а не целым от деления типа INT.

Результат агрегирующего запроса

Пример вкладки Results для блока §3 — одна строка с несколькими агрегатами. Сделайте скриншот для отчёта.

4. NULL в аргументе агрегата

SELECT COUNT(*) AS all_exams, COUNT(MARK) AS with_mark FROM dbo.EXAM_MARKS;

В эталоне у всех 24 строк поле MARK заполнено — оба счётчика дают 24, разница 0. Это нормально: NULL в оценках зарезервирован для других заданий; здесь вы фиксируете, что COUNT(MARK) и COUNT(*) совпали.

Для строк с NULL смотрите §1: COUNT(CITY) vs COUNT(*) у STUDENT.

5. Файл отчёта

  1. Сохраните все запросы §0–4 в lab07_FIO.sql (ФИО латиницей).
  2. В начале: -- ЛР №7, IvanovII, группа ВО-ИСИТ-31.
  3. К каждому блоку добавьте комментарий с ожидаемым значением (как в §1).
  4. Скриншоты: результат §1 (три COUNT); результат §3.2 (оценки); один запрос с AVG и CAST.

Имя файла отчёта: lab07_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab07_IvanovII.sql.

6. Дополнительно

  1. SELECT COUNT(*), COUNT(STIPEND) FROM dbo.STUDENT; — совпадут ли счётчики? Почему?
  2. SELECT AVG(CAST(STIPEND AS FLOAT)) FROM dbo.STUDENT WHERE KURS = 1; — посчитайте вручную для первого курса (подготовка к GROUP BY на ЛР №8).
  3. Чем опасно путать AVG(STIPEND) по всей таблице и среднее «только по получающим стипендию»?

Контрольные вопросы

  1. Почему COUNT(CITY) меньше COUNT(*) у STUDENT?
  2. Чем AVG(STIPEND) по всей таблице отличается от AVG при STIPEND > 0?
  3. Зачем CAST(MARK AS FLOAT) перед AVG?
  4. Что считает COUNT(MARK), если в столбце есть NULL?
  5. Какие MIN/MAX по EXAM_DATE вы получили и что это означает для учебного семестра?

Лабораторная работа №8. GROUP BY, HAVING, ROLLUP

Отчёт: скрипт lab08_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: группировать строки (GROUP BY), отбирать группы через HAVING, строить итоги GROUP BY ROLLUP в SQL Server.

Связь с ЛР №7: там агрегаты считали по всей таблице; здесь — отдельно по каждому курсу, городу, предмету. Справочник эталона — в приложении.

Правило SQL: каждый столбец в SELECT должен быть либо в GROUP BY, либо внутри агрегатной функции (COUNT, AVG, …).

0. Перед началом

USE UniversityDB; SELECT COUNT(*) AS student_cnt FROM dbo.STUDENT;

Ожидается 19 студентов. Если база пуста — повторите ЛР №2.

1. GROUP BY — одно измерение

GROUP BY делит строки на группы с одинаковым значением столбца; агрегат считается внутри каждой группы.

1.1. По курсу

SELECT KURS, COUNT(*) AS cnt, AVG(STIPEND) AS avg_st FROM dbo.STUDENT GROUP BY KURS ORDER BY KURS;

Ожидается 5 строк (курсы 1–5). Пример значений: курс 1 — 6 студентов, средняя стипендия 135.00; курс 2 — 4 студента, 167.50; курс 3 — 4, 96.25; курс 4 — 3, 120.00; курс 5 — 2, 55.00.

1.2. По городу

SELECT CITY, COUNT(*) AS cnt FROM dbo.STUDENT GROUP BY CITY ORDER BY cnt DESC, CITY;

Групп с заполненным городом — 8; отдельная группа с CITY IS NULL (студент 19) — 1 строка. Чаще всего встречаются Воронеж и Москва (по 4 студента).

1.3. По вузу

SELECT UNIVERSITY_ID, COUNT(*) AS cnt, AVG(CAST(STIPEND AS FLOAT)) AS avg_st FROM dbo.STUDENT GROUP BY UNIVERSITY_ID ORDER BY UNIVERSITY_ID;

Ожидается 8 групп (вузы 10, 11, 12, 14, 15, 18, 22, 32). Например: UNIVERSITY_ID = 10 — 5 студентов, средняя стипендия ≈ 95.00; 22 (МГУ) — 4 студента, ≈ 102.50.

Результат GROUP BY KURS

Результат GROUP BY KURS — несколько строк вместо одной сводки с ЛР №7.

2. GROUP BY по оценкам

SELECT SUBJ_ID, COUNT(*) AS exam_cnt, AVG(CAST(MARK AS FLOAT)) AS avg_mark, MIN(MARK) AS min_mark, MAX(MARK) AS max_mark FROM dbo.EXAM_MARKS WHERE MARK IS NOT NULL GROUP BY SUBJ_ID ORDER BY SUBJ_ID;

Ожидается 7 предметов с оценками. Примеры: SUBJ_ID = 10 — 8 экзаменов, средний ≈ 4.00; 43 — 2 экзамена, средний 5.00; 22 — 4 экзамена, средний 3.50.

3. HAVING — фильтр групп

WHERE отбирает строки до группировки; HAVING — группы после агрегации (можно использовать условие на COUNT(*), AVG, …).

3.1. Курсы с более чем тремя студентами

SELECT KURS, COUNT(*) AS cnt FROM dbo.STUDENT GROUP BY KURS HAVING COUNT(*) > 3 ORDER BY KURS;

Ожидается 3 строки: курсы 1 (6), 2 (4), 3 (4). Курсы 4 и 5 отсеялись — в группе ≤ 3 студента.

3.2. Предметы со средним баллом ≥ 4

SELECT SUBJ_ID, AVG(CAST(MARK AS FLOAT)) AS avg_mark FROM dbo.EXAM_MARKS WHERE MARK IS NOT NULL GROUP BY SUBJ_ID HAVING AVG(CAST(MARK AS FLOAT)) >= 4 ORDER BY SUBJ_ID;

Ожидается 6 предметов: 10, 18, 31, 43, 56, 94. Предмет 22 (средний 3.50) в список не попадает.

4. WHERE до GROUP BY

SELECT KURS, AVG(CAST(STIPEND AS FLOAT)) AS avg_st FROM dbo.STUDENT WHERE STIPEND > 0 GROUP BY KURS ORDER BY KURS;

Сначала отбрасываются нулевые стипендии, затем считается среднее по оставшимся в группе. Пример: курс 1 — среднее ≈ 162.00 (5 студентов с ненулевой стипендией), курс 4 — 180.00 (студент 6 с нулём не участвует).

Если написать HAVING AVG(STIPEND) > 0 вместо WHERE STIPEND > 0, нули всё равно войдут в расчёт среднего внутри группы — результат будет другим. Это частая ошибка на защите.

5. ROLLUP

SELECT KURS, COUNT(*) AS cnt, AVG(STIPEND) AS avg_st FROM dbo.STUDENT GROUP BY ROLLUP(KURS) ORDER BY KURS;

ROLLUP добавляет строку с KURS IS NULL — итог по всей таблице: cnt = 19, avg_st ≈ 122.89 (как на ЛР №7 без группировки). Строки с числом в KURS — группы по курсам из §1.1.

6. Файл отчёта

  1. Сохраните запросы §0–5 в lab08_FIO.sql (ФИО латиницей).
  2. В начале: -- ЛР №8, IvanovII, группа ВО-ИСИТ-31.
  3. К каждому блоку — комментарий с числом строк результата и ключевыми значениями.
  4. Скриншоты: GROUP BY KURS; HAVING COUNT(*) > 3; ROLLUP с итоговой строкой NULL.

Имя файла отчёта: lab08_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab08_IvanovII.sql.

7. Дополнительно

  1. GROUP BY KURS, CITY — сколько групп получится? Сравните с группировкой только по KURS.
  2. Почему SELECT KURS, SURNAME, COUNT(*) FROM STUDENT GROUP BY KURS вызывает ошибку?
  3. Добавьте WITH ROLLUP к запросу §3.2 — что изменится в результате?

Контрольные вопросы

  1. Почему столбцы в SELECT должны быть в GROUP BY или внутри агрегата?
  2. Чем HAVING отличается от WHERE?
  3. Зачем фильтровать STIPEND>0 до GROUP BY, а не в HAVING?
  4. Что означает строка с NULL в ROLLUP?
  5. Какие SUBJ_ID имеют средний балл ≥ 4 по вашим данным?

Лабораторная работа №9. Вложенные подзапросы

Отчёт: скрипт lab09_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: писать скалярные подзапросы, использовать IN и NOT IN; понять, почему NOT IN опасен при NULL в подзапросе.

Связь с ЛР №8: там вы считали агрегаты с GROUP BY; здесь тот же MAX/AVG спрятан внутри WHERE — подзапрос возвращает одно значение для сравнения с каждой строкой внешнего запроса.

0. Перед началом

USE UniversityDB; SELECT COUNT(*) AS student_cnt FROM dbo.STUDENT;

Ожидается 19 студентов.

1. Скалярный подзапрос

Скалярный подзапрос возвращает одно значение (одну строку, один столбец). Его ставят в WHERE после =, >, < и т.д. Если вернётся больше одной строки — ошибка.

1.1. Максимальная стипендия

SELECT SURNAME, STIPEND FROM dbo.STUDENT WHERE STIPEND = (SELECT MAX(STIPEND) FROM dbo.STUDENT);

Ожидается 1 строка: Морозова, стипендия 250 (STUDENT_ID = 7).

1.2. Выше средней (только ненулевые стипендии)

SELECT SURNAME, STIPEND FROM dbo.STUDENT WHERE STIPEND > (SELECT AVG(STIPEND) FROM dbo.STUDENT WHERE STIPEND > 0) ORDER BY STIPEND DESC;

Средняя по ненулевым ≈ 155.67. Ожидается 7 строк (Сидорова, Козлова, Морозова, Соколова, Зайцева, Лебедева, Крылова).

1.3. Вузы с рейтингом выше среднего

SELECT UNIVERSITY_NAME, RATING FROM dbo.UNIVERSITY WHERE RATING > (SELECT AVG(RATING) FROM dbo.UNIVERSITY) ORDER BY RATING DESC;

Средний рейтинг ≈ 496.25. Ожидается 3 вуза: НГУ (580), СПбГУ (650), МГУ (700).

Результат подзапроса со стипендией

Результат §1.1 — одна строка с максимальной стипендией.

2. Подзапрос с IN

IN (подзапрос) проверяет, входит ли значение во множество строк подзапроса. Эквивалентно нескольким OR, но короче и читабельнее.

2.1. Студенты московских вузов

SELECT SURNAME, KURS, UNIVERSITY_ID FROM dbo.STUDENT WHERE UNIVERSITY_ID IN ( SELECT UNIVERSITY_ID FROM dbo.UNIVERSITY WHERE CITY = N'Москва' ) ORDER BY SURNAME;

В эталоне в Москве только МГУ (UNIVERSITY_ID = 22). Ожидается 4 студента (Сидорова, Сидоров, Кузнецов, Лебедева).

2.2. Оценки по «Информатике»

SELECT em.STUDENT_ID, em.MARK, em.EXAM_DATE FROM dbo.EXAM_MARKS em WHERE em.SUBJ_ID IN ( SELECT SUBJ_ID FROM dbo.SUBJECT WHERE SUBJ_NAME LIKE N'%информ%' ) ORDER BY em.STUDENT_ID;

Предмет SUBJ_ID = 10 (Информатика). Ожидается 8 строк в EXAM_MARKS по этому предмету.

Тот же результат можно получить через JOIN — на ЛР №11 сравните оба стиля.

3. NOT IN

NOT IN исключает строки, попадающие в список подзапроса. Важно: если подзапрос вернёт хотя бы один NULL, результат внешнего запроса может стать пустым (логика трёхзначная). Поэтому в подзапросе часто пишут WHERE столбец IS NOT NULL.

3.1. Вузы без студентов

SELECT UNIVERSITY_NAME, CITY FROM dbo.UNIVERSITY u WHERE u.UNIVERSITY_ID NOT IN ( SELECT DISTINCT UNIVERSITY_ID FROM dbo.STUDENT WHERE UNIVERSITY_ID IS NOT NULL );

В эталоне студенты есть в каждом из 8 вузов — результат 0 строк. Это нормально: запишите в отчёте «пустой результат — все вузы представлены».

3.2. Студенты без оценок

SELECT s.STUDENT_ID, s.SURNAME, s.NAME FROM dbo.STUDENT s WHERE s.STUDENT_ID NOT IN ( SELECT DISTINCT STUDENT_ID FROM dbo.EXAM_MARKS WHERE STUDENT_ID IS NOT NULL );

Ожидается 1 строка: Медведев (STUDENT_ID = 19) — специально для заданий с NOT EXISTS на ЛР №10.

3.3. Предметы без экзаменов в ведомости

SELECT SUBJ_ID, SUBJ_NAME FROM dbo.SUBJECT WHERE SUBJ_ID NOT IN ( SELECT DISTINCT SUBJ_ID FROM dbo.EXAM_MARKS WHERE SUBJ_ID IS NOT NULL );

Ожидается 1 предмет: Физкультура (SUBJ_ID = 73).

Если убрать WHERE SUBJ_ID IS NOT NULL и в EXAM_MARKS появится строка с SUBJ_ID = NULL, NOT IN может вернуть ноль строк для всех предметов. На ЛР №10 сравните с NOT EXISTS — он NULL не «ломает».

4. Файл отчёта

  1. Сохраните запросы §0–3 в lab09_FIO.sql (ФИО латиницей).
  2. В начале: -- ЛР №9, IvanovII, группа ВО-ИСИТ-31.
  3. К каждому блоку — комментарий -- rows: N и краткий вывод.
  4. Скриншоты: §1.1 (одна строка); §1.2 (семь фамилий); §3.2 (Медведев).

Имя файла отчёта: lab09_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab09_IvanovII.sql.

5. Дополнительно

  1. Перепишите §2.1 через JOIN с UNIVERSITY — совпали ли строки?
  2. WHERE STIPEND > ALL (SELECT STIPEND FROM STUDENT WHERE STIPEND > 0 AND STUDENT_ID <> 7) — кого оставит?
  3. Почему SELECT * FROM STUDENT WHERE STUDENT_ID NOT IN (SELECT STUDENT_ID FROM EXAM_MARKS) без фильтра NULL может вести себя странно, если в EXAM_MARKS появится NULL в STUDENT_ID?

Контрольные вопросы

  1. Когда подзапрос в WHERE должен вернуть ровно одно значение?
  2. Чем IN с подзапросом отличается от JOIN?
  3. Почему NOT IN опасен, если в подзапросе есть NULL?
  4. Как найти студентов без оценок через NOT IN?
  5. Зачем DISTINCT в подзапросе для UNIVERSITY_ID?

Лабораторная работа №10. Коррелированные подзапросы и EXISTS

Отчёт: скрипт lab10_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: писать коррелированные подзапросы; использовать EXISTS, NOT EXISTS, операторы ANY/ALL.

Связь с ЛР №9: там подзапрос был «сам по себе»; здесь внутренний запрос ссылается на строку внешнего (s1.UNIVERSITY_ID) — выполняется заново для каждой строки снаружи.

0. Перед началом

USE UniversityDB;

1. Коррелированный подзапрос

Внутренний SELECT использует столбец внешней строки (s1.UNIVERSITY_ID, s1.KURS). Для каждого студента заново считается средняя стипендия в его вузе на его курсе.

SELECT s1.STUDENT_ID, s1.SURNAME, s1.STIPEND, s1.KURS, s1.UNIVERSITY_ID FROM dbo.STUDENT s1 WHERE s1.STIPEND > ( SELECT AVG(CAST(s2.STIPEND AS FLOAT)) FROM dbo.STUDENT s2 WHERE s2.UNIVERSITY_ID = s1.UNIVERSITY_ID AND s2.KURS = s1.KURS ) ORDER BY s1.UNIVERSITY_ID, s1.KURS, s1.STIPEND DESC;

Ожидается 3 строки: Иванов (ВГУ, 1 курс — выше среднего по группе), Орлов (ЮФУ, 1 курс), Белкин (ВГУ, 3 курс). Нули в знаменателе не мешают — они входят в среднее по группе.

2. EXISTS и NOT EXISTS

EXISTS (подзапрос) возвращает true, если подзапрос вернул хотя бы одну строку. Часто пишут SELECT 1 — важен факт наличия строк, а не их содержимое.

2.1. Вузы, где есть студенты 5-го курса

SELECT u.UNIVERSITY_NAME, u.CITY FROM dbo.UNIVERSITY u WHERE EXISTS ( SELECT 1 FROM dbo.STUDENT s WHERE s.UNIVERSITY_ID = u.UNIVERSITY_ID AND s.KURS = 5 ) ORDER BY u.UNIVERSITY_NAME;

Ожидается 2 вуза: БГУ (студент 16) и МГУ (студент 10).

2.2. Вузы без студентов

SELECT u.UNIVERSITY_NAME FROM dbo.UNIVERSITY u WHERE NOT EXISTS ( SELECT 1 FROM dbo.STUDENT s WHERE s.UNIVERSITY_ID = u.UNIVERSITY_ID );

В эталоне у каждого вуза есть студенты — результат 0 строк (как NOT IN в ЛР №9).

3. EXISTS по оценкам

SELECT s.SURNAME, s.NAME FROM dbo.STUDENT s WHERE EXISTS ( SELECT 1 FROM dbo.EXAM_MARKS em WHERE em.STUDENT_ID = s.STUDENT_ID AND em.MARK = 5 ) ORDER BY s.SURNAME;

Ожидается 8 студентов с хотя бы одной «5» (в эталоне — Иванов, Петров, Козлова, Волков, Кузнецов, Лебедева, Крылова и др.).

SELECT s.STUDENT_ID, s.SURNAME, s.NAME FROM dbo.STUDENT s WHERE NOT EXISTS ( SELECT 1 FROM dbo.EXAM_MARKS em WHERE em.STUDENT_ID = s.STUDENT_ID );

Ожидается 1 строка: Медведев (STUDENT_ID = 19) — тот же результат, что NOT IN на ЛР №9, но без ловушки NULL.

Результат NOT EXISTS

Результат §3 — один студент без оценок.

4. Оператор ALL

SELECT em.STUDENT_ID, em.SUBJ_ID, em.MARK FROM dbo.EXAM_MARKS em WHERE em.MARK IS NOT NULL AND em.MARK >= ALL ( SELECT em2.MARK FROM dbo.EXAM_MARKS em2 WHERE em2.SUBJ_ID = em.SUBJ_ID AND em2.MARK IS NOT NULL ) ORDER BY em.SUBJ_ID, em.STUDENT_ID;

Строки, где оценка максимальна для своего предмета. Ожидается 12 строк (несколько «лучших» по предметам 10, 43, 56, 94 и т.д.). Если для предмета одна оценка — она тоже «максимальна».

Если подзапрос после ALL пуст (нет оценок по предмету), условие для внешней строки не выполняется — такие строки не попадут в результат.

5. Файл отчёта

  1. Сохраните запросы §0–4 в lab10_FIO.sql (ФИО латиницей).
  2. В начале: -- ЛР №10, IvanovII, группа ВО-ИСИТ-31.
  3. К каждому блоку — -- rows: N и пояснение корреляции или EXISTS.
  4. Скриншоты: §1 (3 строки); §3 NOT EXISTS (Медведев); §4 (несколько SUBJ_ID).

Имя файла отчёта: lab10_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab10_IvanovII.sql.

6. Дополнительно

  1. Перепишите §3 NOT EXISTS через LEFT JOIN … WHERE em.STUDENT_ID IS NULL.
  2. Сравните время выполнения (план запроса) IN vs EXISTS для §2.1 — кратко в комментарии.
  3. WHERE STIPEND > ANY (SELECT …) — чем отличается от > ALL?

Контрольные вопросы

  1. Почему коррелированный подзапрос ссылается на s1.UNIVERSITY_ID?
  2. Чем EXISTS отличается от IN при проверке «есть строки»?
  3. Когда NOT EXISTS предпочтительнее NOT IN?
  4. Что вернёт ALL над пустым подзапросом?
  5. Зачем в EXISTS пишут SELECT 1, а не SELECT *?

Лабораторная работа №11. INNER и OUTER JOIN

Отчёт: скрипт lab11_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: соединять таблицы через INNER JOIN и LEFT JOIN; строить отчёты по связям FK; считать агрегаты после JOIN.

Связь с ЛР №9–10: подзапрос с IN можно заменить JOIN — на этой работе учитесь читать и писать явные соединения. Схема FK — в приложении.

0. Перед началом

Нарисуйте цепочку: UNIVERSITY ← STUDENT → EXAM_MARKS → SUBJECT; отдельно SUBJ_LECT связывает SUBJECT и LECTURER. Условие соединения — равенство ключей FK.

USE UniversityDB;

1. INNER JOIN — студент и вуз

INNER JOIN оставляет только строки, для которых есть пара в обеих таблицах. У каждого студента в эталоне есть вуз — потерь строк не будет.

1.1. Список с городом вуза

SELECT s.SURNAME, s.KURS, u.UNIVERSITY_NAME, u.CITY FROM dbo.STUDENT s INNER JOIN dbo.UNIVERSITY u ON s.UNIVERSITY_ID = u.UNIVERSITY_ID ORDER BY u.CITY, s.SURNAME;

Ожидается 19 строк — по числу студентов.

1.2. Студенты вузов не из Воронежа

SELECT s.SURNAME, u.UNIVERSITY_NAME, u.CITY FROM dbo.STUDENT s INNER JOIN dbo.UNIVERSITY u ON s.UNIVERSITY_ID = u.UNIVERSITY_ID WHERE u.CITY <> N'Воронеж' ORDER BY u.UNIVERSITY_NAME, s.SURNAME;

Ожидается 13 строк (студенты вузов в Москве, СПб, Новосибирске и т.д.; вузы ВГУ и ВГМУ в Воронеже отсеяны).

2. Несколько INNER JOIN

2.1. Ведомость: студент, предмет, оценка

SELECT s.SURNAME, sub.SUBJ_NAME, em.MARK, em.EXAM_DATE FROM dbo.EXAM_MARKS em INNER JOIN dbo.STUDENT s ON em.STUDENT_ID = s.STUDENT_ID INNER JOIN dbo.SUBJECT sub ON em.SUBJ_ID = sub.SUBJ_ID ORDER BY s.SURNAME, em.EXAM_DATE;

Ожидается 24 строки — все строки EXAM_MARKS с подставленными фамилиями и названиями предметов.

2.2. Кто какой предмет ведёт

SELECT sub.SUBJ_NAME, l.SURNAME AS lecturer_surname, l.NAME AS lecturer_name FROM dbo.SUBJ_LECT sl INNER JOIN dbo.SUBJECT sub ON sl.SUBJ_ID = sub.SUBJ_ID INNER JOIN dbo.LECTURER l ON sl.LECTURER_ID = l.LECTURER_ID ORDER BY sub.SUBJ_NAME, l.SURNAME;

Ожидается 12 строк — по таблице SUBJ_LECT в приложении.

К отчёту приложите свой скриншот вкладки Results для запроса §2.1 (ожидается 24 строки: фамилия, предмет, оценка, дата).

3. LEFT JOIN

LEFT JOIN сохраняет все строки левой таблицы; если справа нет пары — столбцы справа NULL.

3.1. Все вузы и их студенты

SELECT u.UNIVERSITY_NAME, s.SURNAME FROM dbo.UNIVERSITY u LEFT JOIN dbo.STUDENT s ON u.UNIVERSITY_ID = s.UNIVERSITY_ID ORDER BY u.UNIVERSITY_NAME, s.SURNAME;

Ожидается 19 строк с фамилиями (у каждого вуза есть студенты; «пустых» вузов нет).

3.2. Вузы без студентов

SELECT u.UNIVERSITY_NAME FROM dbo.UNIVERSITY u LEFT JOIN dbo.STUDENT s ON u.UNIVERSITY_ID = s.UNIVERSITY_ID WHERE s.STUDENT_ID IS NULL;

В эталоне — 0 строк. Запишите в отчёте: «все 8 вузов представлены студентами».

3.3. Студенты без оценок

SELECT s.STUDENT_ID, s.SURNAME, s.NAME FROM dbo.STUDENT s LEFT JOIN dbo.EXAM_MARKS em ON s.STUDENT_ID = em.STUDENT_ID WHERE em.STUDENT_ID IS NULL;

Ожидается 1 строка: Медведев (STUDENT_ID = 19) — тот же результат, что NOT EXISTS на ЛР №10.

4. Агрегаты с JOIN

SELECT u.UNIVERSITY_NAME, COUNT(s.STUDENT_ID) AS student_cnt FROM dbo.UNIVERSITY u LEFT JOIN dbo.STUDENT s ON u.UNIVERSITY_ID = s.UNIVERSITY_ID GROUP BY u.UNIVERSITY_NAME ORDER BY u.UNIVERSITY_NAME;

Ожидается 8 строк. Используйте COUNT(s.STUDENT_ID), а не COUNT(*) — иначе вуз без студентов дал бы 1 вместо 0 (в эталоне все счётчики ≥ 1).

SELECT s.SURNAME, AVG(CAST(em.MARK AS FLOAT)) AS avg_mark FROM dbo.STUDENT s LEFT JOIN dbo.EXAM_MARKS em ON s.STUDENT_ID = em.STUDENT_ID AND em.MARK IS NOT NULL GROUP BY s.SURNAME HAVING COUNT(em.MARK) > 0 ORDER BY avg_mark DESC;

Только студенты с оценками; у Медведева строки не будет. Число строк — 18 (19 − 1 без ведомости).

5. Файл отчёта

  1. Сохраните запросы §0–4 и схему связей (фото/скан) в lab11_FIO.sql или приложите схему отдельно в PDF.
  2. В начале: -- ЛР №11, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §1.2; §2.1; §3.3; §4 COUNT по вузам.

Имя файла отчёта: lab11_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab11_IvanovII.sql.

6. Дополнительно

  1. Перепишите §1.2 через подзапрос IN (ЛР №9) — совпали ли строки?
  2. Чем RIGHT JOIN отличается от LEFT JOIN (поменяли таблицы местами)?
  3. Нарисуйте, что произойдёт при JOIN без условия ON (декартово произведение).

Контрольные вопросы

  1. Чем INNER JOIN отличается от LEFT JOIN на примере вузов без студентов?
  2. Почему COUNT(s.STUDENT_ID) и COUNT(*) могут различаться при LEFT JOIN?
  3. Сколько таблиц участвует в ведомости §2.2?
  4. Как найти студента без оценок через LEFT JOIN?
  5. Зачем рисовать схему связей перед сложным JOIN?

Лабораторная работа №12. UNION, EXCEPT, INTERSECT

Отчёт: скрипт lab12_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: объединять результаты нескольких SELECT; понять разницу UNION и UNION ALL; применить множественные операции к эталону UniversityDB.

Связь с ЛР №11: JOIN соединяет таблицы в одном запросе; UNION складывает результаты двух запросов с одинаковым числом столбцов.

0. Перед началом

USE UniversityDB;

В эталоне: 19 студентов, 10 преподавателей, 24 строки EXAM_MARKS; у Медведева (STUDENT_ID=19) нет оценок.

1. Отчёт со JOIN

Средний балл по студенту с названием вуза — закрепление ЛР №11.

SELECT s.KURS, s.SURNAME, u.UNIVERSITY_NAME, AVG(CAST(em.MARK AS FLOAT)) AS avg_mark FROM dbo.STUDENT s INNER JOIN dbo.UNIVERSITY u ON s.UNIVERSITY_ID = u.UNIVERSITY_ID LEFT JOIN dbo.EXAM_MARKS em ON s.STUDENT_ID = em.STUDENT_ID AND em.MARK IS NOT NULL GROUP BY s.KURS, s.SURNAME, u.UNIVERSITY_NAME ORDER BY s.KURS, s.SURNAME;

Ожидается 19 строк; у Медведева avg_mark = NULL.

2. UNION ALL — общий список фамилий

SELECT SURNAME, N'student' AS person_type FROM dbo.STUDENT UNION ALL SELECT SURNAME, N'lecturer' AS person_type FROM dbo.LECTURER ORDER BY SURNAME;

Ожидается 29 строк (19 студентов + 10 преподавателей).

3. INTERSECT и EXCEPT

SELECT CITY FROM dbo.STUDENT WHERE CITY IS NOT NULL INTERSECT SELECT CITY FROM dbo.UNIVERSITY ORDER BY CITY; SELECT CITY FROM dbo.STUDENT WHERE CITY IS NOT NULL EXCEPT SELECT CITY FROM dbo.UNIVERSITY ORDER BY CITY;

INTERSECT — 7 городов (Воронеж, Москва, Новосибирск, Санкт-Петербург, Белгород, Томск, Ростов-на-Дону). EXCEPT — 1 строка: Курск (есть у студентов, нет среди городов вузов).

4. UNION vs UNION ALL

Повторите §2 с UNION вместо UNION ALL. В эталоне фамилии студентов и преподавателей не пересекаются — снова 29 строк. Запишите в отчёте: UNION удаляет дубликаты между двумя наборами; UNION ALL — нет.

5. Топ предметов

SELECT TOP 5 sub.SUBJ_NAME, AVG(CAST(em.MARK AS FLOAT)) AS avg_mark FROM dbo.EXAM_MARKS em JOIN dbo.SUBJECT sub ON em.SUBJ_ID = sub.SUBJ_ID WHERE em.MARK IS NOT NULL GROUP BY sub.SUBJ_NAME HAVING COUNT(*) >= 2 ORDER BY avg_mark DESC;

Только предметы с не менее двух оценок. Ожидается до 5 строк — зафиксируйте фактическое число и значения avg_mark в комментарии -- rows: N.

6. Файл отчёта

  1. Сохраните запросы §0–5 в lab12_FIO.sql.
  2. В начале: -- ЛР №12, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §3 INTERSECT и EXCEPT; §5 TOP 5.

Имя файла отчёта: lab12_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab12_IvanovII.sql.

Контрольные вопросы

  1. Почему в UNION число и типы столбцов должны совпадать?
  2. Чем UNION ALL быстрее UNION?
  3. Что вернёт INTERSECT городов студентов и вузов?
  4. Зачем HAVING COUNT(*) >= 2 в топе предметов?
  5. Когда EXCEPT полезнее NOT IN?

Лабораторная работа №13. Функции строк, чисел, дат

Отчёт: скрипт lab13_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: строковые и дата-функции T-SQL, ROUND, CAST на UniversityDB.

0. Перед началом

USE UniversityDB;

1. Строки

SELECT SURNAME, LEFT(NAME, 1) + N'.' + LEFT(SURNAME, 1) + N'.' AS initials, LEN(SURNAME) AS surname_len FROM dbo.STUDENT; SELECT SURNAME FROM dbo.STUDENT WHERE LEN(SURNAME) = 6; SELECT SURNAME FROM dbo.STUDENT WHERE SURNAME LIKE N'______';

Первый запрос — 19 строк. LEN(SURNAME)=6 — 8 студентов: Петров, Козлова, Новиков, Сидоров, Волков, Павлов, Белкин, Крылова.

2. Даты и возраст

SELECT SURNAME, BIRTHDAY, DATEDIFF(YEAR, BIRTHDAY, GETDATE()) AS age_years FROM dbo.STUDENT WHERE BIRTHDAY IS NOT NULL; SELECT YEAR(BIRTHDAY) AS birth_year, COUNT(*) AS cnt FROM dbo.STUDENT WHERE BIRTHDAY IS NOT NULL GROUP BY YEAR(BIRTHDAY); SELECT COUNT(*) AS exams_in_jan FROM dbo.EXAM_MARKS WHERE EXAM_DATE >= '2026-01-01' AND EXAM_DATE < '2026-02-01';

Ожидается 16 экзаменов в январе 2026 (все даты EXAM_MARKS в эталоне — 2026 год).

3. Числа

SELECT KURS, ROUND(AVG(CAST(STIPEND AS FLOAT)), 2) AS avg_st FROM dbo.STUDENT GROUP BY KURS; SELECT KURS, MAX(STIPEND) - MIN(STIPEND) AS spread FROM dbo.STUDENT GROUP BY KURS;

По каждому курсу — одна строка агрегата (курсы 1–4 в эталоне).

4. CAST

SELECT UNIVERSITY_NAME, CAST(RATING AS NVARCHAR(10)) + N' баллов' AS rating_text FROM dbo.UNIVERSITY;

Ожидается 8 строк — по числу вузов.

5. Файл отчёта

  1. Сохраните запросы §0–4 в lab13_FIO.sql.
  2. В начале: -- ЛР №13, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §1 LEN=6; §2 exams_in_jan; §4 rating_text.

Имя файла отчёта: lab13_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab13_IvanovII.sql.

Контрольные вопросы

  1. Чем LEN отличается от DATALENGTH для NVARCHAR?
  2. Почему DATEDIFF(YEAR,…) может «ошибаться» на день рождения?
  3. Зачем ROUND при AVG стипендии?
  4. Почему фильтр по YEAR(BIRTHDAY) хуже диапазона дат для индекса?
  5. Зачем CAST рейтинга в NVARCHAR перед конкатенацией?

Лабораторная работа №14. CASE, ISNULL, COALESCE

Отчёт: скрипт lab14_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: условные выражения и обработка NULL в SELECT; студент STUDENT_ID=19 (Медведев) с CITY IS NULL.

0. Перед началом

USE UniversityDB; SELECT STUDENT_ID, SURNAME, CITY FROM dbo.STUDENT WHERE CITY IS NULL;

Ожидается 1 строка: STUDENT_ID=19, Медведев, CITY = NULL.

1. CASE для оценок

SELECT STUDENT_ID, SUBJ_ID, MARK, CASE MARK WHEN 5 THEN N'отлично' WHEN 4 THEN N'хорошо' WHEN 3 THEN N'удовлетворительно' WHEN 2 THEN N'неудовлетворительно' ELSE N'нет оценки' END AS mark_text FROM dbo.EXAM_MARKS;

Ожидается 24 строки — все записи ведомости.

2. Категории стипендии

SELECT SURNAME, STIPEND, CASE WHEN STIPEND = 0 THEN N'нет' WHEN STIPEND < 100 THEN N'низкая' WHEN STIPEND <= 150 THEN N'средняя' ELSE N'высокая' END AS stipend_cat FROM dbo.STUDENT;

Ожидается 19 строк — по каждому студенту.

3. COALESCE и ISNULL

SELECT SURNAME, COALESCE(CITY, N'не указан') AS city_display FROM dbo.STUDENT; SELECT SURNAME, ISNULL(CAST(CITY AS NVARCHAR(40)), N'не указан') AS city2 FROM dbo.STUDENT;

У Медведева в обоих запросах — не указан вместо NULL.

4. IIF и сортировка NULL

SELECT SURNAME, IIF(STIPEND > 0, N'да', N'нет') AS has_stipend FROM dbo.STUDENT; SELECT SURNAME, CITY FROM dbo.STUDENT ORDER BY CASE WHEN CITY IS NULL THEN 1 ELSE 0 END, CITY;

Во втором запросе Медведев с NULL — в конце списка.

5. GROUP BY CASE

SELECT CASE WHEN STIPEND = 0 THEN N'нет' WHEN STIPEND < 100 THEN N'низкая' WHEN STIPEND <= 150 THEN N'средняя' ELSE N'высокая' END AS cat, COUNT(*) AS cnt FROM dbo.STUDENT GROUP BY CASE WHEN STIPEND = 0 THEN N'нет' WHEN STIPEND < 100 THEN N'низкая' WHEN STIPEND <= 150 THEN N'средняя' ELSE N'высокая' END;

Ожидается 4 строки — по числу категорий стипендии.

6. Файл отчёта

  1. Сохраните запросы §0–5 в lab14_FIO.sql.
  2. В начале: -- ЛР №14, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §0 NULL город; §3 COALESCE; §4 ORDER BY.

Имя файла отчёта: lab14_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab14_IvanovII.sql.

Контрольные вопросы

  1. Чем простой CASE отличается от searched CASE?
  2. Чем COALESCE отличается от ISNULL?
  3. Зачем выводить «не указан» для NULL города?
  4. Как ORDER BY CASE ставит NULL в конец?
  5. Почему GROUP BY CASE повторяет выражение из SELECT?

Лабораторная работа №15. Переменные и IF

Отчёт: скрипт lab15_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: объявление переменных DECLARE/SET, ветвление IF/ELSE, проверка IF EXISTS в T-SQL.

0. Перед началом

USE UniversityDB;

1. Переменная курса

DECLARE @kurs INT = 3; SELECT STUDENT_ID, SURNAME, KURS FROM dbo.STUDENT WHERE KURS = @kurs;

При @kurs = 3 ожидается 4 студента.

2. IF по средней стипендии

DECLARE @avg DECIMAL(10,2); SELECT @avg = AVG(STIPEND) FROM dbo.STUDENT WHERE STIPEND > 0; IF @avg > 120 PRINT N'Средняя стипендия выше 120: ' + CAST(@avg AS NVARCHAR(20)); ELSE PRINT N'Средняя стипендия не выше 120: ' + CAST(@avg AS NVARCHAR(20));

Результат PRINT — на вкладке Messages в SSMS.

3. IF EXISTS — студенты без оценок

IF EXISTS ( SELECT 1 FROM dbo.STUDENT s WHERE NOT EXISTS (SELECT 1 FROM dbo.EXAM_MARKS em WHERE em.STUDENT_ID = s.STUDENT_ID) ) PRINT N'Есть студенты без экзаменов'; ELSE PRINT N'У всех студентов есть оценки';

Ожидается сообщение «Есть студенты без экзаменов» (Медведев, STUDENT_ID=19).

4. Файл отчёта

  1. Сохраните запросы §0–3 в lab15_FIO.sql.
  2. В начале: -- ЛР №15, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §1 SELECT при @kurs=3; §2 и §3 — вкладка Messages.

Имя файла отчёта: lab15_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab15_IvanovII.sql.

Контрольные вопросы

  1. Почему имя переменной начинается с @?
  2. Чем IF EXISTS лучше COUNT(*) > 0?
  3. Где увидеть результат PRINT в SSMS?
  4. Можно ли DECLARE @kurs внутри каждого пакета GO отдельно?
  5. Зачем фильтровать STIPEND>0 перед AVG?

Лабораторная работа №16. Циклы WHILE и TRY/CATCH

Отчёт: скрипт lab16_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: цикл WHILE, обработка ошибок TRY/CATCH, транзакция с откатом.

0. Перед началом

USE UniversityDB;

1. WHILE — числа 1..10

DECLARE @i INT = 1; DECLARE @nums TABLE (n INT); WHILE @i <= 10 BEGIN INSERT INTO @nums (n) VALUES (@i); SET @i = @i + 1; END SELECT * FROM @nums;

Ожидается 10 строк — числа от 1 до 10.

2. TRY/CATCH — неверный FK

BEGIN TRY UPDATE dbo.STUDENT SET UNIVERSITY_ID = 999 WHERE STUDENT_ID = 1; END TRY BEGIN CATCH SELECT ERROR_NUMBER() AS err_num, ERROR_MESSAGE() AS err_msg; END CATCH;

Ожидается строка с err_num (нарушение FK) — без изменения данных.

3. CHECK на MARK

BEGIN TRY INSERT INTO dbo.EXAM_MARKS (EXAM_ID, STUDENT_ID, SUBJ_ID, MARK, EXAM_DATE) VALUES (99999, 1, 10, 6, GETDATE()); END TRY BEGIN CATCH SELECT ERROR_NUMBER(), ERROR_MESSAGE(); END CATCH;

Оценка 6 вне диапазона CHECK — попадание в CATCH, строка не вставляется.

4. TRAN + TRY/CATCH

BEGIN TRY BEGIN TRAN; UPDATE dbo.STUDENT SET STIPEND = STIPEND - 500 WHERE STUDENT_ID = 1; UPDATE dbo.STUDENT SET STIPEND = STIPEND + 500 WHERE STUDENT_ID = 3; COMMIT TRAN; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRAN; SELECT ERROR_NUMBER(), ERROR_MESSAGE(); END CATCH;

При успехе стипендии студентов 1 и 3 не меняются в сумме; при ошибке — ROLLBACK.

5. Файл отчёта

  1. Сохраните запросы §0–4 в lab16_FIO.sql.
  2. В начале: -- ЛР №16, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §1 @nums; §2 и §3 — блок CATCH.

Имя файла отчёта: lab16_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab16_IvanovII.sql.

Контрольные вопросы

  1. Чем табличная переменная @nums отличается от #temp?
  2. Что вернёт ERROR_NUMBER() при нарушении FK?
  3. Почему INSERT с MARK=6 попадает в CATCH?
  4. Зачем проверять @@TRANCOUNT перед ROLLBACK?
  5. Как связаны TRY/CATCH и лекция 5 про ACID?

Лабораторная работа №17. XML в SQL Server

Отчёт: скрипт lab17_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: тип XML, методы .value() и .query(); связь с лекциями 9–10.

0. Перед началом

USE UniversityDB;

1. Таблица с XML

IF OBJECT_ID(N'dbo.UnivXml', N'U') IS NOT NULL DROP TABLE dbo.UnivXml; CREATE TABLE dbo.UnivXml ( univ_id INT NOT NULL PRIMARY KEY, payload XML NOT NULL );

2. Загрузка фрагмента ВГУ

INSERT INTO dbo.UnivXml (univ_id, payload) VALUES (10, N'<Univ id="10"> <Name>Воронежский государственный университет</Name> <City>Воронеж</City> <Student id="1" kurs="2">Иванов</Student> <Student id="3" kurs="3">Петров</Student> </Univ>');

Ожидается 1 строка в UnivXml для univ_id=10 (ВГУ).

3. value() — одно поле

SELECT univ_id, payload.value(N'(/Univ/Name)[1]', N'NVARCHAR(80)') AS univ_name, payload.value(N'(/Univ/City)[1]', N'NVARCHAR(40)') AS city FROM dbo.UnivXml;

Ожидается название ВГУ и город Воронеж.

4. query() — список студентов

SELECT univ_id, payload.query(N'//Student') AS students_xml FROM dbo.UnivXml; SELECT stu.stu.value(N'@id', N'int') AS student_id, stu.stu.value(N'.', N'NVARCHAR(50)') AS surname FROM dbo.UnivXml x CROSS APPLY x.payload.nodes(N'//Student') AS stu(stu);

Во втором запросе — 2 строки (Иванов, Петров из XML).

5. PRIMARY XML INDEX (обзорно)

Если права позволяют:

CREATE PRIMARY XML INDEX PXI_UnivXml ON dbo.UnivXml(payload);

Иначе в отчёте опишите: индекс ускоряет XPath-запросы к большим документам.

6. Файл отчёта

  1. Сохраните запросы §0–5 в lab17_FIO.sql.
  2. В начале: -- ЛР №17, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §3 value(); §4 nodes().

Имя файла отчёта: lab17_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab17_IvanovII.sql.

Контрольные вопросы

  1. Чем XML-столбец отличается от NVARCHAR(MAX)?
  2. Что делает .value() с XPath (/Univ/Name)[1]?
  3. Зачем CROSS APPLY … nodes()?
  4. Когда нужен PRIMARY XML INDEX?
  5. Как XML в этой работе связан с лекцией 10?

Лабораторная работа №18. Иерархические данные

Отчёт: скрипт lab18_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: рекурсивный CTE по таблице ORG_UNIT в UniversityDB; сравнение adjacency list и nested sets.

0. Перед началом

USE UniversityDB; SELECT * FROM dbo.ORG_UNIT ORDER BY UNIT_ID;

В эталоне 10 строк в ORG_UNIT (иерархии ВГУ и МГУ).

1. Рекурсивный CTE — потомки ВГУ

WITH org_tree AS ( SELECT UNIT_ID, UNIT_NAME, PARENT_ID, CAST(UNIT_NAME AS NVARCHAR(400)) AS path, 0 AS lvl FROM dbo.ORG_UNIT WHERE UNIT_ID = 1 UNION ALL SELECT c.UNIT_ID, c.UNIT_NAME, c.PARENT_ID, CAST(p.path + N' / ' + c.UNIT_NAME AS NVARCHAR(400)), p.lvl + 1 FROM dbo.ORG_UNIT c INNER JOIN org_tree p ON c.PARENT_ID = p.UNIT_ID ) SELECT UNIT_ID, UNIT_NAME, path, lvl FROM org_tree ORDER BY path;

От корня UNIT_ID=1 (ВГУ) ожидается 7 строк — всё поддерево вуза 10.

2. Отступ в отчёте

WITH org_tree AS ( SELECT UNIT_ID, UNIT_NAME, PARENT_ID, 0 AS lvl FROM dbo.ORG_UNIT WHERE UNIT_ID = 1 UNION ALL SELECT c.UNIT_ID, c.UNIT_NAME, c.PARENT_ID, p.lvl + 1 FROM dbo.ORG_UNIT c JOIN org_tree p ON c.PARENT_ID = p.UNIT_ID ) SELECT REPLICATE(N' ', lvl) + UNIT_NAME AS tree_view, lvl FROM org_tree ORDER BY UNIT_ID;

Столбец lvl — уровень вложенности (0 у ректората, 1 у факультетов и т.д.).

3. Теория в отчёте

Кратко сравните adjacency list (PARENT_ID, как в ORG_UNIT) и nested sets (left/right): плюсы и минусы каждой модели.

4. Файл отчёта

  1. Сохраните запросы §0–2 в lab18_FIO.sql.
  2. В начале: -- ЛР №18, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: §1 path/lvl; §2 tree_view.

Имя файла отчёта: lab18_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab18_IvanovII.sql.

Контрольные вопросы

  1. Где в CTE задаётся якорь рекурсии?
  2. Что будет, если в PARENT_ID появится цикл?
  3. Зачем столбец lvl или path в результате?
  4. Когда nested sets выигрывают у parent_id?
  5. Как ORG_UNIT связана с иерархией подразделений вуза?

Лабораторная работа №19. MongoDB — нереляционная БД

Отчёт: скриншоты Compass + lab19_FIO.pdf (ФИО латиницей).

Цель: документная модель в MongoDB Compass; сравнение с реляционной строкой dbo.STUDENT.

Стенд: MongoDB Compass на учебном ПК (или MongoDB Atlas по указанию преподавателя). SQL Server для сравнения — UniversityDB.

0. Перед началом

  1. Установите/откройте MongoDB Compass.
  2. Создайте базу University и коллекцию students.
  3. В SSMS выполните USE UniversityDB; — данные для документов возьмите из STUDENT + UNIVERSITY.

1. Пять документов

Вставьте минимум пять документов с полями _id, surname, name, kurs, вложенный объект university: { name, city }:

{ "_id": 1, "surname": "Иванов", "name": "Иван", "kurs": 2, "university": { "name": "ВГУ", "city": "Воронеж" } }

Данные можно взять из:

SELECT TOP 5 s.STUDENT_ID, s.SURNAME, s.NAME, s.KURS, u.UNIVERSITY_NAME, u.CITY FROM dbo.STUDENT s JOIN dbo.UNIVERSITY u ON s.UNIVERSITY_ID = u.UNIVERSITY_ID;

Ожидается 5 документов в коллекции students.

2. find, filter, projection

db.students.find({ "kurs": 3 }) db.students.find( { "kurs": { "$gte": 2 } }, { surname: 1, kurs: 1, "university.city": 1 } )

Зафиксируйте число документов при фильтре kurs: 3 — в эталоне SQL при KURS=3 четыре студента.

3. insert, update, delete

db.students.insertOne({ "_id": 99, "surname": "Тестов", "kurs": 1 }) db.students.updateOne({ "_id": 99 }, { "$set": { "kurs": 2 } }) db.students.deleteOne({ "_id": 99 })

После deleteOne документ 99 отсутствует — приложите скриншот.

4. Отчёт PDF

  1. Оформите lab19_FIO.pdf: скриншоты Compass, примеры запросов.
  2. Ответьте: чем документ MongoDB отличается от строки STUDENT+JOIN UNIVERSITY.
  3. Укажите, где в документе денормализация (город вуза внутри студента).

Имя файла отчёта: lab19_FIO.pdf (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab19_IvanovII.pdf.

Контрольные вопросы

  1. Чем коллекция MongoDB отличается от таблицы SQL Server?
  2. Зачем вложенный объект university вместо UNIVERSITY_ID?
  3. Чем find с projection отличается от SELECT с списком столбцов?
  4. Когда денормализация в MongoDB оправдана?
  5. Какие аномалии обновления появляются при дублировании city в каждом документе?

Лабораторная работа №20. Представления VIEW

Отчёт: скрипт lab20_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: создать представления VIEW на UniversityDB, упростить доступ к JOIN и проверить чтение через представление.

Связь с лекцией 12: VIEW — сохранённый запрос с именем, а не копия таблицы.

0. Перед началом

USE UniversityDB;

1. VIEW студент + вуз

CREATE OR ALTER VIEW dbo.v_StudentUniv AS SELECT s.STUDENT_ID, s.SURNAME, s.NAME, s.KURS, u.UNIVERSITY_NAME, u.CITY, u.RATING FROM dbo.STUDENT s INNER JOIN dbo.UNIVERSITY u ON s.UNIVERSITY_ID = u.UNIVERSITY_ID; GO SELECT TOP 10 * FROM dbo.v_StudentUniv ORDER BY SURNAME;

VIEW содержит 19 строк — по числу студентов.

2. VIEW успеваемости

CREATE OR ALTER VIEW dbo.v_StudentMarks AS SELECT s.STUDENT_ID, s.SURNAME, sub.SUBJ_NAME, em.MARK, em.EXAM_DATE FROM dbo.EXAM_MARKS em JOIN dbo.STUDENT s ON em.STUDENT_ID = s.STUDENT_ID JOIN dbo.SUBJECT sub ON em.SUBJ_ID = sub.SUBJ_ID; GO SELECT * FROM dbo.v_StudentMarks WHERE MARK = 5;

Во VIEW — 24 строки; фильтр MARK=5 — 9 пятёрок в эталоне.

3. SCHEMABINDING (обзорно)

Объясните в комментарии к скрипту: WITH SCHEMABINDING защищает определение VIEW от изменения базовых столбцов.

4. Удаление VIEW

-- в конце работы по договорённости: -- DROP VIEW IF EXISTS dbo.v_StudentMarks; -- DROP VIEW IF EXISTS dbo.v_StudentUniv;

5. Файл отчёта

  1. Сохраните запросы §0–4 в lab20_FIO.sql.
  2. В начале: -- ЛР №20, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншот SELECT из v_StudentUniv и v_StudentMarks WHERE MARK=5.

Имя файла отчёта: lab20_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab20_IvanovII.sql.

Контрольные вопросы

  1. Чем VIEW отличается от таблицы в Object Explorer?
  2. Обновляются ли данные в VIEW при изменении STUDENT?
  3. Зачем прятать JOIN за v_StudentUniv для пользователя отчётов?
  4. Можно ли INSERT в простой VIEW — когда да?
  5. Как VIEW связано с INSTEAD OF триггером (ЛР №22)?

Лабораторная работа №21. Хранимые процедуры

Отчёт: скрипт lab21_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: создать и вызвать хранимые процедуры на T-SQL, в том числе usp_StudentByKurs из лекции 12.

0. Перед началом

USE UniversityDB;

1. Процедура usp_StudentByKurs

CREATE OR ALTER PROC dbo.usp_StudentByKurs @kurs INT AS BEGIN SET NOCOUNT ON; SELECT STUDENT_ID, SURNAME, NAME, KURS, UNIVERSITY_ID FROM dbo.STUDENT WHERE KURS = @kurs ORDER BY SURNAME; END; GO EXEC dbo.usp_StudentByKurs @kurs = 2; EXEC dbo.usp_StudentByKurs @kurs = 3;

При @kurs = 3 ожидается 4 студента.

2. Процедура со средней стипендией по вузу

CREATE OR ALTER PROC dbo.usp_AvgStipendByUniv @univ_id INT AS BEGIN SELECT @univ_id AS university_id, AVG(CAST(STIPEND AS FLOAT)) AS avg_stipend FROM dbo.STUDENT WHERE UNIVERSITY_ID = @univ_id AND STIPEND > 0; END; GO EXEC dbo.usp_AvgStipendByUniv @univ_id = 10;

3. OUTPUT-параметр (дополнительно)

CREATE OR ALTER PROC dbo.usp_AvgStipendOut @univ_id INT, @avg DECIMAL(10,2) OUTPUT AS BEGIN SELECT @avg = AVG(CAST(STIPEND AS FLOAT)) FROM dbo.STUDENT WHERE UNIVERSITY_ID = @univ_id AND STIPEND > 0; END; GO DECLARE @result DECIMAL(10,2); EXEC dbo.usp_AvgStipendOut @univ_id = 10, @avg = @result OUTPUT; SELECT @result AS avg_stipend;

4. Очистка

-- DROP PROC IF EXISTS dbo.usp_AvgStipendOut; -- DROP PROC IF EXISTS dbo.usp_AvgStipendByUniv; -- DROP PROC IF EXISTS dbo.usp_StudentByKurs;

5. Файл отчёта

  1. Сохраните запросы §0–4 в lab21_FIO.sql.
  2. В начале: -- ЛР №21, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: EXEC @kurs=3; OUTPUT @result.

Имя файла отчёта: lab21_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab21_IvanovII.sql.

Контрольные вопросы

  1. Чем EXEC процедуры отличается от ad-hoc SELECT?
  2. Зачем SET NOCOUNT ON внутри процедуры?
  3. Как передать OUTPUT-параметр при EXEC?
  4. Почему логику usp_StudentByKurs удобно хранить на сервере?
  5. Как GRANT EXECUTE связано с ЛР №23?

Лабораторная работа №22. Триггеры DML и INSTEAD OF

Отчёт: скрипт lab22_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: создать AFTER-триггер аудита на EXAM_MARKS и INSTEAD OF INSERT на представление v_StudentUniv.

0. Перед началом

USE UniversityDB; IF OBJECT_ID(N'dbo.v_StudentUniv', N'V') IS NULL EXEC(N'CREATE VIEW dbo.v_StudentUniv AS SELECT s.*, u.UNIVERSITY_NAME FROM dbo.STUDENT s JOIN dbo.UNIVERSITY u ON s.UNIVERSITY_ID = u.UNIVERSITY_ID');

1. Таблица аудита

IF OBJECT_ID(N'dbo.AuditLog', N'U') IS NULL CREATE TABLE dbo.AuditLog ( log_id INT IDENTITY(1,1) PRIMARY KEY, evt NVARCHAR(100) NOT NULL, evt_time DATETIME2 NOT NULL DEFAULT SYSDATETIME() );

2. AFTER INSERT, UPDATE, DELETE

CREATE OR ALTER TRIGGER dbo.trg_ExamAudit ON dbo.EXAM_MARKS AFTER INSERT, UPDATE, DELETE AS BEGIN SET NOCOUNT ON; INSERT INTO dbo.AuditLog (evt) VALUES (N'EXAM_MARKS changed'); END; GO

Измените оценку в транзакции с ROLLBACK и проверьте SELECT * FROM dbo.AuditLog; — после ROLLBACK записей аудита не останется.

3. Запрет уменьшения оценки

CREATE OR ALTER TRIGGER dbo.trg_ExamNoDowngrade ON dbo.EXAM_MARKS AFTER UPDATE AS BEGIN IF EXISTS ( SELECT 1 FROM inserted i JOIN deleted d ON i.EXAM_ID = d.EXAM_ID WHERE i.MARK < d.MARK ) BEGIN RAISERROR(N'Нельзя уменьшать оценку', 16, 1); ROLLBACK TRAN; END END; GO

4. INSTEAD OF INSERT на VIEW

CREATE OR ALTER TRIGGER dbo.trg_StudentUnivInsert ON dbo.v_StudentUniv INSTEAD OF INSERT AS BEGIN INSERT INTO dbo.STUDENT (STUDENT_ID, NAME, SURNAME, KURS, UNIVERSITY_ID, STIPEND, CITY, BIRTHDAY) SELECT i.STUDENT_ID, i.NAME, i.SURNAME, i.KURS, u.UNIVERSITY_ID, 0, u.CITY, NULL FROM inserted i JOIN dbo.UNIVERSITY u ON u.UNIVERSITY_NAME = i.UNIVERSITY_NAME; END; GO

Объясните в отчёте: VIEW с JOIN не всегда updatable — INSTEAD OF перенаправляет INSERT на базовые таблицы.

5. Очистка

DROP TRIGGER IF EXISTS dbo.trg_StudentUnivInsert ON dbo.v_StudentUniv; DROP TRIGGER IF EXISTS dbo.trg_ExamNoDowngrade ON dbo.EXAM_MARKS; DROP TRIGGER IF EXISTS dbo.trg_ExamAudit ON dbo.EXAM_MARKS;

6. Файл отчёта

  1. Сохраните запросы §0–5 в lab22_FIO.sql.
  2. В начале: -- ЛР №22, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: AuditLog; ошибка при уменьшении оценки.

Имя файла отчёта: lab22_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab22_IvanovII.sql.

Контрольные вопросы

  1. Чем таблицы inserted и deleted отличаются в триггере?
  2. Когда нужен AFTER, а когда INSTEAD OF?
  3. Почему INSERT в v_StudentUniv без триггера может не работать?
  4. Зачем ROLLBACK внутри триггера при RAISERROR?
  5. Чем триггер отличается от CHECK constraint?

Лабораторная работа №23. GRANT, REVOKE, роли

Отчёт: скрипт lab23_FIO.sql (ФИО латиницей) + скриншоты результатов.

Цель: login, user, database role; выдать минимальные права на UniversityDB; связь с лекцией 14.

На общем сервере класса создавайте логины только по указанию преподавателя; в конце работы удалите тестовые учётные записи.

0. Перед началом

USE UniversityDB;

1. Логины и пользователи (на тестовом экземпляре)

USE master; CREATE LOGIN reader_test WITH PASSWORD = N'Strong_Pass_123!', CHECK_POLICY = OFF; CREATE LOGIN clerk_test WITH PASSWORD = N'Strong_Pass_456!', CHECK_POLICY = OFF; USE UniversityDB; CREATE USER reader_user FOR LOGIN reader_test; CREATE USER clerk_user FOR LOGIN clerk_test;

2. Роли

CREATE ROLE role_read; CREATE ROLE role_marks; GRANT SELECT ON dbo.STUDENT TO role_read; GRANT SELECT ON dbo.UNIVERSITY TO role_read; GRANT SELECT, INSERT, UPDATE ON dbo.EXAM_MARKS TO role_marks; ALTER ROLE role_read ADD MEMBER reader_user; ALTER ROLE role_marks ADD MEMBER clerk_user;

3. Проверка отказа

Подключитесь вторым окном SSMS как reader_test и попробуйте:

INSERT INTO dbo.STUDENT (STUDENT_ID, NAME, SURNAME, KURS, UNIVERSITY_ID, STIPEND) VALUES (90, N'X', N'X', 1, 10, 0);

Ожидается отказ — нет INSERT на STUDENT (только SELECT через role_read).

4. REVOKE и EXECUTE

REVOKE SELECT ON dbo.LECTURER FROM role_read; GRANT EXECUTE ON dbo.usp_StudentByKurs TO role_read;

После GRANT EXECUTE пользователь reader_test может вызвать процедуру без прямого SELECT на LECTURER.

5. Очистка

DROP USER IF EXISTS reader_user; DROP USER IF EXISTS clerk_user; USE master; DROP LOGIN IF EXISTS reader_test; DROP LOGIN IF EXISTS clerk_test;

6. Файл отчёта

  1. Сохраните скрипт §0–5 в lab23_FIO.sql.
  2. В начале: -- ЛР №23, IvanovII, группа ВО-ИСИТ-31.
  3. Скриншоты: ошибка INSERT под reader_test; успешный SELECT или EXEC.

Имя файла отчёта: lab23_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab23_IvanovII.sql.

Контрольные вопросы

  1. Чем login отличается от user в базе?
  2. Зачем принцип минимальных привилегий для ФИО студентов?
  3. Почему reader не может INSERT в STUDENT после GRANT SELECT?
  4. Зачем GRANT EXECUTE на процедуру вместо SELECT на таблицу?
  5. Что произойдёт, если не DROP LOGIN после лабораторной?

Лабораторная работа №24. Восстановление данных и итоговый практикум

Отчёт: lab24_FIO.sql (ФИО латиницей) + защита.

Цель: резервное копирование и восстановление (лекции 13–14) + комплексный практикум по материалам семестра на UniversityDB.

0. Перед началом

  1. Убедитесь, что UniversityDB в эталонном состоянии: 19 студентов, 24 оценки.
  2. Согласуйте с преподавателем каталог для файлов .bak на учебном сервере.
USE UniversityDB; SELECT COUNT(*) AS student_cnt FROM dbo.STUDENT; SELECT COUNT(*) AS mark_cnt FROM dbo.EXAM_MARKS;

Часть A. Резервное копирование и восстановление

A.1. Полная копия

BACKUP DATABASE UniversityDB TO DISK = N'C:\Temp\univ_lab24_full.bak' WITH INIT, STATS = 10;

A.2. Изменение данных

BEGIN TRAN; UPDATE dbo.STUDENT SET STIPEND = STIPEND + 100 WHERE KURS = 1; SELECT SURNAME, STIPEND FROM dbo.STUDENT WHERE KURS = 1; ROLLBACK TRAN;

A.3. Восстановление на копию базы

RESTORE DATABASE UniversityDB_restore FROM DISK = N'C:\Temp\univ_lab24_full.bak' WITH MOVE N'UniversityDB' TO N'C:\Temp\univ_restore.mdf', MOVE N'UniversityDB_log' TO N'C:\Temp\univ_restore_log.ldf', REPLACE, RECOVERY;

Если нет прав — приложите скриншоты SSMS и текстовый план RESTORE.

A.4. Теория в отчёте

Опишите цепочку FULL / DIFF / LOG backup и когда нужен STOPAT.

Часть B. Итоговый практикум (8 из 10)

Выполните минимум восемь пунктов ниже; каждый — отдельный блок в lab24_FIO.sql с комментарием.

  1. JOIN трёх таблиц + фильтр по городу или курсу.
  2. GROUP BY + HAVING (средний балл по предметам).
  3. Подзапрос или EXISTS (студенты без оценок — ожидается Медведев).
  4. CREATE VIEW + SELECT из VIEW.
  5. Процедура usp_StudentByKurs с @kurs=3 — 4 строки.
  6. AFTER-триггер аудита (с DROP TRIGGER в конце скрипта).
  7. План запроса: Index Seek vs Scan для фильтра по CITY.
  8. Демонстрация GRANT/REVOKE или описание, если нет прав.
  9. Рекурсивный CTE по ORG_UNIT от UNIT_ID=1 — 7 строк.
  10. Фрагмент XML в dbo.UnivXml (если таблица ещё есть с ЛР №17).

Файл отчёта

  1. Сохраните части A и B в lab24_FIO.sql.
  2. В начале: -- ЛР №24, IvanovII, группа ВО-ИСИТ-31.
  3. Подготовьтесь к защите на занятии.

Имя файла отчёта: lab24_FIO.sql (ФИО латиницей) — вместо FIO подставьте фамилию и инициалы латиницей, например lab24_IvanovII.sql.

Контрольные вопросы

  1. Чем BACKUP DATABASE отличается от RESTORE DATABASE?
  2. Зачем восстанавливать на UniversityDB_restore, а не поверх боевой базы?
  3. Какие три темы SQL вы считаете сильными после семестра?
  4. Что проверяет экзамен по дисциплине?
  5. Как связаны лабораторные №1–24 с лекциями курса?

Учебный план

№ТемаВидЧасыМатериал курса
Раздел 1. Основы баз данных и проектирование (нед. 1–3)
1Основные понятия баз данных и СУБДЛек2Л.1
2SSMS: системные и учебные БДЛаб2ЛР №1
3Реляционная модель. Функциональные зависимостиЛек2Л.2
4Таблицы и первый SELECTЛаб2ЛР №2
5Нормализация. Аномалии обновленияЛек2Л.3
6DDL: CREATE, типы, ограниченияЛаб2ЛР №3
7FK, ALTER TABLE, индексыЛаб2ЛР №4
Раздел 2. SQL: выборка и изменение данных (нед. 4)
8Многопользовательские и распределённые БДЛек2Л.4
9INSERT, SELECT, WHEREЛаб2ЛР №5
10UPDATE, DELETE, ORDER BYЛаб2ЛР №6
Раздел 3. Транзакции и многопользовательский доступ (нед. 5–8)
11Транзакции. Свойства ACIDЛек2Л.5
12Агрегатные функцииЛаб2ЛР №7
13GROUP BY, HAVING, ROLLUPЛаб2ЛР №8
14Аномалии параллельного доступаЛек2Л.6
15Вложенные подзапросыЛаб2ЛР №9
16Коррелированные подзапросы и EXISTSЛаб2ЛР №10
17Уровни изоляции транзакцийЛек2Л.7
18INNER и OUTER JOINЛаб2ЛР №11
19UNION, EXCEPT, INTERSECTЛаб2ЛР №12
20Блокировки, тупики, репликацияЛек2Л.8
21Функции строк, чисел, датЛаб2ЛР №13
22CASE, ISNULL, COALESCEЛаб2ЛР №14
Раздел 4. XML, иерархии и нереляционные модели (нед. 9–10)
23Структурированные и неструктурированные данныеЛек2Л.9
24Переменные и IFЛаб2ЛР №15
25Циклы WHILE и TRY/CATCHЛаб2ЛР №16
26Язык XMLЛек2Л.10
27XML в SQL ServerЛаб2ЛР №17
28Иерархические данныеЛаб2ЛР №18
Раздел 5. Администрирование и программирование в СУБД (нед. 11–12)
29Администрирование и мониторинг СУБДЛек2Л.11
30MongoDB — документная БДЛаб2ЛР №19
31Представления VIEWЛаб2ЛР №20
32Программирование в БД: процедуры, триггерыЛек2Л.12
33Хранимые процедурыЛаб2ЛР №21
34Триггеры DML и INSTEAD OFЛаб2ЛР №22
Раздел 6. Резервное копирование и защита данных (нед. 13–14)
35Резервное копированиеЛек2Л.13
36GRANT, REVOKE, ролиЛаб2ЛР №23
37Восстановление данных и защитаЛек2Л.14
38Восстановление данных и итоговый практикумЛаб2ЛР №24
Раздел 7. Распределённые БД и хранилища данных (нед. 15–16)
39Распределённые БД и двухфазная фиксацияЛек2Л.15 · курсовые №6, 21
40Хранилища данных и подготовка к экзаменуЛек2Л.16 · билеты
Раздел 8. Итоговая аттестация
41Экзамен по дисциплине «Управление данными»ИКР2,3Экзамен · вопросы

Соответствие лекций и лабораторных

Краткая карта: какая лекция подводит к каким ЛР на UniversityDB (ЛР №19 — MongoDB).

ЛекцияТемаЛРНа практике
Л.1Понятия БД, СУБД, SSMS№1CREATE DATABASE, подключение
Л.2Реляционная модель, ФЗ№2таблицы, INSERT, SELECT
Л.3Нормализация, ключи№3–4DDL, FK, ALTER, индексы
Л.4Многопользовательский доступ№5–6DML, WHERE, UPDATE, DELETE
Л.5ACID, транзакции№7–8агрегаты, GROUP BY
Л.6Аномалии параллельного доступа№9–10подзапросы, EXISTS
Л.7Уровни изоляции№11–12JOIN, UNION
Л.8Блокировки, тупики, репликация№13–14функции, CASE
Л.9Структурированные / неструктурированные данные№15–16переменные, TRY/CATCH
Л.10XML, XSD№17–18XML в SQL Server, CTE-иерархии
Л.11Администрирование, мониторинг№19–20MongoDB, VIEW
Л.12Процедуры, триггеры, планы№21–22процедуры, триггеры
Л.13Резервное копирование№23GRANT, роли
Л.14Восстановление, защита данных№24BACKUP/RESTORE + практикум
Л.15Распределённые БД, 2PC—теория · курсовые №6, 21
Л.16OLAP, подготовка к экзамену—вопросы · билеты

Объём занятий

ВидКоличествоАкадем. часы
Лекции16 пар32
Лабораторные24 пары48
Итого контакт40 пар80
Экзамен (ИКР)12,3

Курсовая работа

Что должно быть в любой курсовой (минимум)

  1. Предметная область — краткое описание задачи «своими словами» (1–2 страницы): кто пользуется системой, какие данные хранятся, зачем нужна БД.
  2. Проектирование — ER-диаграмма (сущности, связи 1:N и M:N), список функциональных зависимостей, обоснование нормализации (1НФ–3НФ) и выбор ключей.
  3. Реализация в SQL Server — отдельная база Kursovaya_FIO (или согласованное имя); не менее 5 таблиц с PRIMARY KEY, FOREIGN KEY, минимум два ограничения CHECK или UNIQUE; осмысленное наполнение (не «пустые таблицы»).
  4. Запросы и логика — не менее 8 SQL-запросов разного типа: SELECT с WHERE, JOIN, агрегаты с GROUP BY/HAVING, подзапрос или EXISTS; плюс один из элементов серверного программирования: VIEW, хранимая процедура или AFTER-триггер (аудит или бизнес-правило).
  5. Надёжность данных — один сценарий с BEGIN TRAN … COMMIT/ROLLBACK (операция из нескольких шагов) или демонстрация резервного копирования своей базы (BACKUP / описание RESTORE).
  6. Отчёт — скрипт kursovaya_FIO.sql (ФИО латиницей) + пояснительная записка со скриншотами SSMS (схема, примеры запросов, при наличии — план выполнения или права доступа).

Свою тему (не из списка) можно предложить преподавателю, если она укладывается в минимум выше и не дублирует UniversityDB «одной таблицей Excel».

№Тема и содержание проекта
1Интернет-магазин. Спроектировать БД: товары, категории, клиенты, заказы, строки заказа. Реализовать оформление заказа в транзакции; отчёты — топ товаров, сумма по клиентам; VIEW «активные заказы».
2Частная клиника. Пациенты, врачи, приёмы, диагнозы, назначения. Связи M:N «врач — специализация»; CHECK на дату приёма; процедура «расписание врача на неделю».
3Автосервис. Клиенты, автомобили, заказ-наряды, работы, запчасти. FK «авто → владелец»; агрегат «выручка по месяцам»; триггер аудита изменения стоимости наряда.
4Гостиница. Номера, типы номеров, бронирования, гости, оплаты. Запрет пересечения броней (CHECK или триггер); JOIN «загрузка номеров»; резервная копия перед тестовым наполнением.
5Публичная библиотека. Книги, авторы, экземпляры, читатели, выдачи. Нормализация «автор не дублируется в каждой выдаче»; EXISTS «книги на руках у читателя»; процедура выдачи/возврата.
6Фитнес-клуб. Абонементы, типы, посещения, тренеры, групповые занятия. GROUP BY «популярность занятий»; транзакция продления абонемента; VIEW для ресепшена.
7Ресторан / доставка. Меню, блюда, ингредиенты, заказы, курьеры. M:N «блюдо — ингредиент»; HAVING «блюда дороже среднего»; XML-описание акции (столбец XML, извлечение поля).
8Агентство недвижимости. Объекты, типы, районы, клиенты, сделки, агенты. Иерархия районов (рекурсивный CTE); подзапрос «объекты без сделок»; индекс по цене + комментарий к плану запроса.
9Ветеринарная клиника. Владельцы, питомцы, породы, приёмы, вакцинации. CHECK на вид животного; LEFT JOIN «питомцы без приёмов за год»; роли «ветеринар / регистратор» (GRANT на уровне учебного login).
10Музыкальная школа. Ученики, преподаватели, инструменты, уроки, абонементы. Расписание без двойного бронирования кабинета; GROUP BY «часы по преподавателям»; процедура usp_LessonsByTeacher.
11Фото-студия. Клиенты, пакеты услуг, брони слотов, фотографы, оборудование. Транзакция «бронь + предоплата»; VIEW «загрузка студии по дням»; миграция прайса из Excel (описать шаги загрузки).
12Прокат велосипедов. Пункты проката, велосипеды, клиенты, аренды, штрафы. FK и CASCADE при списании велосипеда; отчёт «простой парка»; BACKUP после наполнения эталоном.
13Кафе настольных игр. Игры, жанры, столы, брони, участники турниров. M:N «турнир — игрок»; EXISTS «игроки без турниров»; триггер запрета удаления игры с активными бронями.
14Центр репетиторства. Предметы, репетиторы, ученики, занятия, оплаты. Нормализация «не хранить ФИО репетитора в каждой оплате»; JOIN «долги учеников»; процедура отчёта за период.
15Цветочный магазин. Букеты, компоненты, поставщики, заказы, доставки. CHECK на сезонность/остаток; UNION «все контактные лица (клиенты + поставщики)»; VIEW для витрины заказов.
16IT-Helpdesk. Пользователи, категории заявок, тикеты, комментарии, исполнители. Статусы и история (таблица аудита или триггер); GROUP BY «среднее время закрытия»; демонстрация блокировки при параллельном UPDATE статуса.
17Садовое товарищество. Участки, владельцы, взносы, показания счётчиков, обращения. Иерархия «улица — участок»; агрегаты по задолженности; сравнение «плохая одна таблица» vs нормализованная схема в записке.
18Приют для животных. Питомцы, породы, поступления, усыновления, волонтёры, пожертвования. NOT EXISTS «давно не усыновлённые»; транзакция «усыновление + закрытие карточки»; этичные тестовые данные без реальных ФИО.
19Коворкинг. Помещения, рабочие места, тарифы, брони, резиденты. Рекурсивный CTE по зонам этажа; процедура поиска свободного места; RESTORE на копию Kursovaya_FIO_restore после ошибочного DELETE.
20Кинотеатр. Залы, сеансы, фильмы, места, билеты, кассиры. Уникальность «место + сеанс»; JOIN «заполняемость сеансов»; VIEW для онлайн-расписания; индекс по дате сеанса.
21Прачечная / химчистка. Клиенты, изделия, услуги, приёмы в работу, статусы, оплаты. CHECK на допустимый статус; GROUP BY «выручка по видам услуг»; сценарий ROLLBACK при ошибочном массовом UPDATE.
22Каршеринг (локальный парк). Автомобили, тарифы, поездки, клиенты, штрафы, ТО. FK и даты; подзапрос «клиенты с поездками > N»; описание RPO/RTO для такой БД в записке.
23Музей. Экспонаты, залы, эпохи, экскурсии, гиды, билеты. M:N «экскурсия — экспонат»; агрегат «посещаемость по залам»; хранение текста экспозиции в XML с выборкой XPath.
24Спортивная секция. Секции, тренеры, спортсмены, соревнования, результаты, медосмотры. GROUP BY «медали по секциям»; процедура зачисления в секцию; GRANT «тренер видит только свою секцию» через VIEW и права.
25Своя тема (по согласованию). Любая предметная область студента: от онлайн-курсов до складского учёта — при условии выполнения минимума из списка выше и защиты ER-схемы на консультации до сдачи.

Приложение. Учебная база UniversityDB

UniversityDB — единая учебная база курса: вузы, студенты, преподаватели, предметы, оценки; с ЛР №3 — группы (ACADEMIC_GROUP) и учебная библиотека (LIB_*). После лабораторных с изменением данных (DML, триггеры) базу можно восстановить, заново выполнив блоки ниже.

Что такое SQL-скрипт и откуда он взялся

SQL-скрипт — это обычный текст с командами T-SQL: создание таблиц, вставка строк, запросы. В SSMS его набирают или вставляют в окно New Query и выполняют клавишей F5 (или кнопкой Execute). Сервер выполняет команды и сохраняет результат в файлах базы на диске — не в окне SSMS.

Эталонный скрипт UniversityDB собран для этого курса и лежит на этой странице — отдельного файла скачивать не нужно. Ниже он разбит на блоки с пояснениями. На ЛР №2 вы копируете блоки по порядку в SSMS и сохраняете свою копию в файл lab02_FIO.sql (ФИО латиницей) — это уже ваш рабочий файл, а не «чужой скрипт из ниоткуда».

  1. Откройте SSMS, подключитесь к серверу, выберите базу UniversityDB.
  2. New Query — вставьте блок 1 (или пропустите, если база уже создана на ЛР №1).
  3. Блоки 3–5 — CREATE TABLE. Блок 6 — INSERT. Между частями с GO можно выполнять по очереди.
  4. Таблицы ниже на странице — те же данные в виде, удобном для чтения; в SSMS нужен именно SQL из блоков.

Схема связей

UNIVERSITY 1—∞ STUDENT, UNIVERSITY 1—∞ LECTURER, UNIVERSITY 1—∞ ORG_UNIT.
SUBJECT 1—∞ EXAM_MARKS, STUDENT 1—∞ EXAM_MARKS.
LECTURER ∞—∞ SUBJECT через SUBJ_LECT.
ORG_UNIT.PARENT_ID ссылается на ORG_UNIT.UNIT_ID (иерархия).

Сборка базы по шагам (SQL Server)

Выполняйте блоки по порядку. Если база пустая после ЛР №1, блок 2 можно пропустить.

Блок 1. База данных

Создаёт базу UniversityDB, если её ещё нет, и переключает контекст на неё. На ЛР №1 вы уже делали то же командой CREATE DATABASE — здесь повтор для полного эталона.

-- UniversityDB для Microsoft SQL Server IF DB_ID(N'UniversityDB') IS NULL CREATE DATABASE UniversityDB; GO USE UniversityDB; GO SET NOCOUNT ON;

Блок 2. Очистка старых таблиц (по необходимости)

Нужен только если таблицы уже создавали и хотите пересобрать схему с нуля. Удаление идёт от зависимых таблиц к независимым — иначе СУБД не даст удалить родительскую таблицу.

IF OBJECT_ID('dbo.LIB_COPY') IS NOT NULL DROP TABLE dbo.LIB_COPY; IF OBJECT_ID('dbo.LIB_BOOK') IS NOT NULL DROP TABLE dbo.LIB_BOOK; IF OBJECT_ID('dbo.LIB_AUTHOR') IS NOT NULL DROP TABLE dbo.LIB_AUTHOR; IF OBJECT_ID('dbo.ACADEMIC_GROUP') IS NOT NULL DROP TABLE dbo.ACADEMIC_GROUP; IF OBJECT_ID('dbo.SUBJ_LECT') IS NOT NULL DROP TABLE dbo.SUBJ_LECT; IF OBJECT_ID('dbo.EXAM_MARKS') IS NOT NULL DROP TABLE dbo.EXAM_MARKS; IF OBJECT_ID('dbo.ORG_UNIT') IS NOT NULL DROP TABLE dbo.ORG_UNIT; IF OBJECT_ID('dbo.STUDENT') IS NOT NULL DROP TABLE dbo.STUDENT; IF OBJECT_ID('dbo.LECTURER') IS NOT NULL DROP TABLE dbo.LECTURER; IF OBJECT_ID('dbo.SUBJECT') IS NOT NULL DROP TABLE dbo.SUBJECT; IF OBJECT_ID('dbo.UNIVERSITY') IS NOT NULL DROP TABLE dbo.UNIVERSITY; GO

Блок 3. Справочники без внешних ключей

Таблицы, на которые ссылаются другие: список вузов и список предметов. Создаются первыми.

CREATE TABLE dbo.UNIVERSITY ( UNIVERSITY_ID INT CONSTRAINT PK_UNIVERSITY PRIMARY KEY, UNIVERSITY_NAME NVARCHAR(80) NOT NULL, RATING INT, CITY NVARCHAR(40) NOT NULL ); CREATE TABLE dbo.SUBJECT ( SUBJ_ID INT CONSTRAINT PK_SUBJECT PRIMARY KEY, SUBJ_NAME NVARCHAR(80) NOT NULL, HOUR INT NOT NULL, SEMESTER INT NOT NULL, CONSTRAINT CK_SUBJECT_HOUR CHECK (HOUR > 0), CONSTRAINT CK_SUBJECT_SEM CHECK (SEMESTER BETWEEN 1 AND 12) ); GO

Блок 4. Студенты и преподаватели

У каждой строки — ссылка UNIVERSITY_ID на справочник вузов (внешний ключ). Именно так устроена схема из лекции 2.

CREATE TABLE dbo.STUDENT ( STUDENT_ID INT CONSTRAINT PK_STUDENT PRIMARY KEY, SURNAME NVARCHAR(50) NOT NULL, NAME NVARCHAR(50) NOT NULL, STIPEND DECIMAL(10,2) NOT NULL CONSTRAINT DF_STIPEND DEFAULT (0), KURS INT NOT NULL, CITY NVARCHAR(40) NULL, BIRTHDAY DATE NULL, UNIVERSITY_ID INT NOT NULL, CONSTRAINT CK_STUDENT_KURS CHECK (KURS BETWEEN 1 AND 6), CONSTRAINT CK_STUDENT_STIP CHECK (STIPEND >= 0), CONSTRAINT FK_STUDENT_UNIVERSITY FOREIGN KEY (UNIVERSITY_ID) REFERENCES dbo.UNIVERSITY(UNIVERSITY_ID) ); CREATE TABLE dbo.LECTURER ( LECTURER_ID INT CONSTRAINT PK_LECTURER PRIMARY KEY, SURNAME NVARCHAR(50) NOT NULL, NAME NVARCHAR(50) NOT NULL, CITY NVARCHAR(40) NOT NULL, UNIVERSITY_ID INT NOT NULL, CONSTRAINT FK_LECTURER_UNIVERSITY FOREIGN KEY (UNIVERSITY_ID) REFERENCES dbo.UNIVERSITY(UNIVERSITY_ID) ); GO

Блок 5. Оценки, связи и подразделения

EXAM_MARKS — оценка студента по предмету. SUBJ_LECT — кто какой предмет ведёт. ORG_UNIT — иерархия кафедр (нужна на ЛР №18).

CREATE TABLE dbo.EXAM_MARKS ( EXAM_ID INT CONSTRAINT PK_EXAM PRIMARY KEY, STUDENT_ID INT NOT NULL, SUBJ_ID INT NOT NULL, MARK INT NULL, EXAM_DATE DATE NOT NULL, CONSTRAINT CK_MARK CHECK (MARK IS NULL OR MARK BETWEEN 2 AND 5), CONSTRAINT FK_EXAM_ST FOREIGN KEY (STUDENT_ID) REFERENCES dbo.STUDENT(STUDENT_ID), CONSTRAINT FK_EXAM_SUB FOREIGN KEY (SUBJ_ID) REFERENCES dbo.SUBJECT(SUBJ_ID) ); CREATE TABLE dbo.SUBJ_LECT ( LECTURER_ID INT NOT NULL, SUBJ_ID INT NOT NULL, CONSTRAINT PK_SUBJ_LECT PRIMARY KEY (LECTURER_ID, SUBJ_ID), CONSTRAINT FK_SL_L FOREIGN KEY (LECTURER_ID) REFERENCES dbo.LECTURER(LECTURER_ID), CONSTRAINT FK_SL_S FOREIGN KEY (SUBJ_ID) REFERENCES dbo.SUBJECT(SUBJ_ID) ); CREATE TABLE dbo.ORG_UNIT ( UNIT_ID INT CONSTRAINT PK_ORG PRIMARY KEY, PARENT_ID INT NULL, UNIT_NAME NVARCHAR(80) NOT NULL, UNIVERSITY_ID INT NOT NULL, CONSTRAINT FK_ORG_PARENT FOREIGN KEY (PARENT_ID) REFERENCES dbo.ORG_UNIT(UNIT_ID), CONSTRAINT FK_ORG_UNIVERSITY FOREIGN KEY (UNIVERSITY_ID) REFERENCES dbo.UNIVERSITY(UNIVERSITY_ID) ); GO

Блок 6. Эталонные данные (INSERT)

Строки вставляются в порядке зависимостей: сначала родители (UNIVERSITY, SUBJECT), потом дети. Иначе внешний ключ не найдёт ссылку и INSERT завершится ошибкой.

6.1. Вузы:

INSERT INTO dbo.UNIVERSITY VALUES (10,N'ВГУ',450,N'Воронеж'),(11,N'НГУ',580,N'Новосибирск'), (12,N'СПбГУ',650,N'Санкт-Петербург'),(14,N'БГУ',320,N'Белгород'), (15,N'ТГУ',390,N'Томск'),(18,N'ВГМУ',410,N'Воронеж'), (22,N'МГУ',700,N'Москва'),(32,N'ЮФУ',470,N'Ростов-на-Дону');

6.2. Предметы:

INSERT INTO dbo.SUBJECT VALUES (10,N'Информатика',56,1),(18,N'Химия',40,2),(22,N'Физика',34,1),(31,N'Базы данных',72,5), (43,N'Математика',56,2),(56,N'История',34,4),(73,N'Физкультура',34,5),(94,N'Английский',56,3);

6.3. Студенты (19 строк; у id=19 город NULL — для заданий с IS NULL):

INSERT INTO dbo.STUDENT VALUES (1,N'Иванов',N'Иван',150,1,N'Воронеж','2007-03-12',10), (2,N'Сидорова',N'Анна',200,1,N'Москва','2007-07-01',22), (3,N'Петров',N'Пётр',0,3,N'Курск','2005-11-20',10), (4,N'Козлова',N'Мария',180,2,N'Санкт-Петербург','2006-04-15',12), (5,N'Новиков',N'Дмитрий',120,2,N'Новосибирск','2006-09-03',11), (6,N'Сидоров',N'Вадим',0,4,N'Москва','2004-01-28',22), (7,N'Морозова',N'Елена',250,1,N'Белгород','2007-12-05',14), (8,N'Волков',N'Алексей',140,3,N'Томск','2005-06-17',15), (9,N'Соколова',N'Ирина',160,2,N'Воронеж','2006-02-22',18), (10,N'Кузнецов',N'Борис',0,5,N'Москва','2003-08-09',22), (11,N'Орлов',N'Никита',130,1,N'Ростов-на-Дону','2007-05-14',32), (12,N'Зайцева',N'Ольга',170,4,N'Воронеж','2004-10-30',10), (13,N'Павлов',N'Андрей',90,3,N'Новосибирск','2005-03-08',11), (14,N'Лебедева',N'Татьяна',210,2,N'Москва','2006-12-19',22), (15,N'Котов',N'Павел',0,1,N'Курск','2008-01-11',10), (16,N'Лукин',N'Артём',110,5,N'Белгород','2003-04-25',14), (17,N'Белкин',N'Вадим',155,3,N'Воронеж','2005-09-16',10), (18,N'Крылова',N'Светлана',190,4,N'Санкт-Петербург','2004-07-07',12), (19,N'Медведев',N'Олег',80,1,NULL,'2007-08-21',32);

6.4. Преподаватели:

INSERT INTO dbo.LECTURER VALUES (24,N'Колесников',N'Борис',N'Воронеж',10),(46,N'Никонов',N'Иван',N'Воронеж',10), (74,N'Лагутин',N'Павел',N'Москва',22),(108,N'Струков',N'Николай',N'Москва',22), (276,N'Николаев',N'Виктор',N'Воронеж',10),(328,N'Сорокин',N'Андрей',N'Орёл',10), (401,N'Смирнова',N'Ольга',N'Санкт-Петербург',12),(512,N'Гусев',N'Игорь',N'Новосибирск',11), (620,N'Фролов',N'Сергей',N'Томск',15),(705,N'Макарова',N'Анна',N'Белгород',14);

6.5. Оценки (24 строки; у студента 19 оценок нет — для NOT EXISTS и LEFT JOIN):

INSERT INTO dbo.EXAM_MARKS VALUES (1,1,10,5,'2026-01-15'),(2,1,22,4,'2026-01-18'),(3,3,10,3,'2026-01-15'),(4,3,22,4,'2026-01-18'), (5,2,10,5,'2026-01-16'),(6,4,43,5,'2026-06-10'),(7,5,10,4,'2026-01-15'),(8,6,56,3,'2026-06-12'), (9,8,94,5,'2026-01-20'),(10,9,18,4,'2026-06-08'),(11,10,31,5,'2026-01-22'),(12,12,56,4,'2026-06-12'), (13,13,10,2,'2026-01-15'),(14,14,94,5,'2026-01-20'),(15,17,22,3,'2026-01-18'),(16,7,10,5,'2026-01-16'), (17,11,10,4,'2026-01-16'),(18,15,22,3,'2026-01-18'),(19,18,56,5,'2026-06-12'),(20,16,31,4,'2026-01-22'), (21,1,43,5,'2026-06-10'),(22,12,31,3,'2026-01-22'),(23,6,31,4,'2026-01-22'),(24,4,10,4,'2026-01-16');

6.6. Кто какой предмет ведёт:

INSERT INTO dbo.SUBJ_LECT VALUES (24,10),(24,31),(46,22),(46,18),(74,43),(108,56),(276,73),(328,10),(401,94),(512,10),(620,18),(705,56);

6.7. Подразделения вузов:

INSERT INTO dbo.ORG_UNIT VALUES (1,NULL,N'Ректорат',10),(2,1,N'Учебное управление',10),(3,1,N'Факультет КНиИТ',10), (4,3,N'Кафедра информационных технологий',10),(5,3,N'Кафедра математики',10), (6,1,N'Факультет ПММ',10),(7,6,N'Кафедра механики',10), (20,NULL,N'Ректорат',22),(21,20,N'Факультет ВМК',22),(22,21,N'Кафедра алгоритмических языков',22);

Проверка после блока 6: SELECT COUNT(*) FROM STUDENT; — должно быть 19. У студента с STUDENT_ID = 19 нет строк в EXAM_MARKS.

SQLite (если работаете не в SSMS)

PRAGMA foreign_keys = ON; CREATE TABLE UNIVERSITY ( UNIVERSITY_ID INTEGER PRIMARY KEY, UNIVERSITY_NAME TEXT NOT NULL, RATING INTEGER, CITY TEXT NOT NULL ); -- остальные таблицы аналогично; DATE храните как TEXT 'YYYY-MM-DD' -- DECIMAL заменить на REAL или INTEGER копеек -- NVARCHAR заменить на TEXT -- IDENTITY не нужен при явных id

Данные в таблицах (для просмотра)

Те же строки, что в блоке 6, в удобном виде — можно сверить результат после INSERT.

На телефоне широкие таблицы прокручиваются пальцем влево и вправо.

UNIVERSITY

UNIVERSITY_IDUNIVERSITY_NAMERATINGCITY
10ВГУ450Воронеж
11НГУ580Новосибирск
12СПбГУ650Санкт-Петербург
14БГУ320Белгород
15ТГУ390Томск
18ВГМУ410Воронеж
22МГУ700Москва
32ЮФУ470Ростов-на-Дону

STUDENT (19 строк)

IDФамилияИмяСтип.КурсГородРождениеВуз
1ИвановИван1501Воронеж2007-03-1210
2СидороваАнна2001Москва2007-07-0122
3ПетровПётр03Курск2005-11-2010
4КозловаМария1802Санкт-Петербург2006-04-1512
5НовиковДмитрий1202Новосибирск2006-09-0311
6СидоровВадим04Москва2004-01-2822
7МорозоваЕлена2501Белгород2007-12-0514
8ВолковАлексей1403Томск2005-06-1715
9СоколоваИрина1602Воронеж2006-02-2218
10КузнецовБорис05Москва2003-08-0922
11ОрловНикита1301Ростов-на-Дону2007-05-1432
12ЗайцеваОльга1704Воронеж2004-10-3010
13ПавловАндрей903Новосибирск2005-03-0811
14ЛебедеваТатьяна2102Москва2006-12-1922
15КотовПавел01Курск2008-01-1110
16ЛукинАртём1105Белгород2003-04-2514
17БелкинВадим1553Воронеж2005-09-1610
18КрыловаСветлана1904Санкт-Петербург2004-07-0712
19МедведевОлег801NULL2007-08-2132

LECTURER

IDФамилияИмяГородВуз
24КолесниковБорисВоронеж10
46НиконовИванВоронеж10
74ЛагутинПавелМосква22
108СтруковНиколайМосква22
276НиколаевВикторВоронеж10
328СорокинАндрейОрёл10
401СмирноваОльгаСанкт-Петербург12
512ГусевИгорьНовосибирск11
620ФроловСергейТомск15
705МакароваАннаБелгород14

SUBJECT

SUBJ_IDНазваниеЧасыСеместр
10Информатика561
18Химия402
22Физика341
31Базы данных725
43Математика562
56История344
73Физкультура345
94Английский563

EXAM_MARKS (24 строки)

EXAM_IDSTUDENT_IDSUBJ_IDMARKEXAM_DATE
111052026-01-15
212242026-01-18
331032026-01-15
432242026-01-18
521052026-01-16
644352026-06-10
751042026-01-15
865632026-06-12
989452026-01-20
1091842026-06-08
11103152026-01-22
12125642026-06-12
13131022026-01-15
14149452026-01-20
15172232026-01-18
1671052026-01-16
17111042026-01-16
18152232026-01-18
19185652026-06-12
20163142026-01-22
2114352026-06-10
22123132026-01-22
2363142026-01-22
2441042026-01-16

Студент 19 (Медведев) специально без строк в EXAM_MARKS и с CITY NULL: на нём проверяют IS NULL, NOT EXISTS и LEFT JOIN … IS NULL.

SUBJ_LECT

LECTURER_IDSUBJ_ID
2410
2431
4622
4618
7443
10856
27673
32810
40194
51210
62018
70556

ORG_UNIT (для ЛР №18)

UNIT_IDPARENT_IDUNIT_NAMEUNIVERSITY_ID
1NULLРекторат10
21Учебное управление10
31Факультет КНиИТ10
43Кафедра информационных технологий10
53Кафедра математики10
61Факультет ПММ10
76Кафедра механики10
20NULLРекторат22
2120Факультет ВМК22
2221Кафедра алгоритмических языков22

Шпаргалка диалектов

ЗадачаSQL ServerSQLite
Первые N строкTOP (N) … ORDER BYLIMIT N
ПагинацияOFFSET FETCHLIMIT … OFFSET
Строка сейчасGETDATE(), SYSDATETIME()datetime('now')
Конкатенация+ или CONCAT||
АвточислоINT IDENTITYINTEGER PRIMARY KEY
Юникод-литералN'текст''текст' UTF-8
Удаление дубликатов строк запросаDISTINCTDISTINCT
FULL JOINестьэмуляция UNION
ПроцедурыCREATE PROCнет
БэкапBACKUP DATABASEVACUUM INTO / копия файла

Экзамен

Контрольные вопросы

На экзамене из этого списка задают два вопроса (см. билеты ниже).

  1. Данные, БД, СУБД. Отличие. Примеры.
  2. Недостатки файлового подхода. Преимущества БД.
  3. Архитектура ANSI/SPARC. Независимость данных.
  4. Реляционная модель: отношение, домен, ключи.
  5. Функциональная зависимость. Тривиальные и полные ФЗ.
  6. Аксиомы Армстронга. Замыкание атрибутов. Поиск ключа.
  7. Аномалии обновления, вставки, удаления. Пример.
  8. 1НФ, 2НФ, 3НФ. Определения и пример декомпозиции.
  9. НФБК. Чем строже 3НФ. Пример с потерей ФЗ.
  10. Идея 4НФ и многозначной зависимости (кратко).
  11. Транзакция. Команды BEGIN, COMMIT, ROLLBACK, SAVEPOINT.
  12. Свойства ACID. Что СУБД не гарантирует.
  13. Грязное, неповторяемое чтение, фантом, потерянное обновление.
  14. Уровни изоляции SQL-92. Таблица аномалий. Умолчание SQL Server.
  15. Блокировки S/X. Двухфазный протокол.
  16. Тупик: граф ожидания, жертва, профилактика. Ошибка 1205.
  17. SQLite vs SQL Server (опционально, кратко).
  18. Задачи администратора БД. Login, user, роль, GRANT.
  19. План выполнения. Scan и Seek. Зачем индекс и когда вреден.
  20. RPO и RTO. Полная, разностная копия, журнал. Правило 3-2-1.
  21. RESTORE: порядок, NORECOVERY, STOPAT. Логическая ошибка vs потеря диска.
  22. Распределённая БД. Виды репликации. Идея 2PC.
  23. OLTP и OLAP. Хранилище, факт, измерение, операции куба.
  24. VIEW, CTE, хранимая процедура, триггер: назначение и отличия.

Экзаменационные билеты

Скачать билеты (.docx)

Билеты к экзамену

На экзамене выдаётся один билет из списка ниже: два теоретических вопроса + одна SQL-задача по UniversityDB. Нажмите на номер билета, чтобы открыть.

Билет №1
  1. Данные, БД, СУБД. Отличие. Примеры.
  2. НФБК. Чем строже 3НФ. Пример с потерей ФЗ.
  3. SQL: Студенты со стипендией выше средней по своему вузу.
Билет №2
  1. Недостатки файлового подхода. Преимущества БД.
  2. Идея 4НФ и многозначной зависимости (кратко).
  3. SQL: Вузы без студентов (NOT EXISTS или LEFT JOIN … IS NULL).
Билет №3
  1. Архитектура ANSI/SPARC. Независимость данных.
  2. Транзакция. Команды BEGIN, COMMIT, ROLLBACK, SAVEPOINT.
  3. SQL: Средний балл по предметам 1-го семестра (GROUP BY, HAVING).
Билет №4
  1. Реляционная модель: отношение, домен, ключи.
  2. Свойства ACID. Что СУБД не гарантирует.
  3. SQL: Иногородние студенты (город студента не совпадает с городом вуза).
Билет №5
  1. Функциональная зависимость. Тривиальные и полные ФЗ.
  2. Грязное, неповторяемое чтение, фантом, потерянное обновление.
  3. SQL: Преподаватели, ведущие предмет «Информатика» (через SUBJ_LECT).
Билет №6
  1. Аксиомы Армстронга. Замыкание атрибутов. Поиск ключа.
  2. Уровни изоляции SQL-92. Таблица аномалий. Умолчание SQL Server.
  3. SQL: Число оценок «5» по каждому вузу.
Билет №7
  1. Аномалии обновления, вставки, удаления. Пример.
  2. Блокировки S/X. Двухфазный протокол.
  3. SQL: Студенты с CITY IS NULL (ожидается Медведев, STUDENT_ID=19).
Билет №8
  1. 1НФ, 2НФ, 3НФ. Определения и пример декомпозиции.
  2. Тупик: граф ожидания, жертва, профилактика. Ошибка 1205.
  3. SQL: Рекурсивный CTE: подразделения вуза UNIVERSITY_ID=10 от UNIT_ID=1.
Билет №9
  1. НФБК. Чем строже 3НФ. Пример с потерей ФЗ.
  2. SQLite vs SQL Server (кратко).
  3. SQL: Студенты со стипендией выше средней по своему вузу.
Билет №10
  1. Идея 4НФ и многозначной зависимости (кратко).
  2. Задачи администратора БД. Login, user, роль, GRANT.
  3. SQL: Вузы без студентов (NOT EXISTS или LEFT JOIN … IS NULL).
Билет №11
  1. Транзакция. Команды BEGIN, COMMIT, ROLLBACK, SAVEPOINT.
  2. План выполнения. Scan и Seek. Зачем индекс и когда вреден.
  3. SQL: Средний балл по предметам 1-го семестра (GROUP BY, HAVING).
Билет №12
  1. Свойства ACID. Что СУБД не гарантирует.
  2. RPO и RTO. Полная, разностная копия, журнал. Правило 3-2-1.
  3. SQL: Иногородние студенты (город студента не совпадает с городом вуза).
Билет №13
  1. Грязное, неповторяемое чтение, фантом, потерянное обновление.
  2. RESTORE: порядок, NORECOVERY, STOPAT. Логическая ошибка vs потеря диска.
  3. SQL: Преподаватели, ведущие предмет «Информатика» (через SUBJ_LECT).
Билет №14
  1. Уровни изоляции SQL-92. Таблица аномалий. Умолчание SQL Server.
  2. Распределённая БД. Виды репликации. Идея 2PC.
  3. SQL: Число оценок «5» по каждому вузу.
Билет №15
  1. Блокировки S/X. Двухфазный протокол.
  2. OLTP и OLAP. Хранилище, факт, измерение, операции куба.
  3. SQL: Студенты с CITY IS NULL (ожидается Медведев, STUDENT_ID=19).
Билет №16
  1. Тупик: граф ожидания, жертва, профилактика. Ошибка 1205.
  2. VIEW, CTE, хранимая процедура, триггер: назначение и отличия.
  3. SQL: Рекурсивный CTE: подразделения вуза UNIVERSITY_ID=10 от UNIT_ID=1.
Билет №17
  1. SQLite vs SQL Server (кратко).
  2. Данные, БД, СУБД. Отличие. Примеры.
  3. SQL: Студенты со стипендией выше средней по своему вузу.
Билет №18
  1. Задачи администратора БД. Login, user, роль, GRANT.
  2. Недостатки файлового подхода. Преимущества БД.
  3. SQL: Вузы без студентов (NOT EXISTS или LEFT JOIN … IS NULL).
Билет №19
  1. План выполнения. Scan и Seek. Зачем индекс и когда вреден.
  2. Архитектура ANSI/SPARC. Независимость данных.
  3. SQL: Средний балл по предметам 1-го семестра (GROUP BY, HAVING).
Билет №20
  1. RPO и RTO. Полная, разностная копия, журнал. Правило 3-2-1.
  2. Реляционная модель: отношение, домен, ключи.
  3. SQL: Иногородние студенты (город студента не совпадает с городом вуза).
Билет №21
  1. RESTORE: порядок, NORECOVERY, STOPAT. Логическая ошибка vs потеря диска.
  2. Функциональная зависимость. Тривиальные и полные ФЗ.
  3. SQL: Преподаватели, ведущие предмет «Информатика» (через SUBJ_LECT).
Билет №22
  1. Распределённая БД. Виды репликации. Идея 2PC.
  2. Аксиомы Армстронга. Замыкание атрибутов. Поиск ключа.
  3. SQL: Число оценок «5» по каждому вузу.
Билет №23
  1. OLTP и OLAP. Хранилище, факт, измерение, операции куба.
  2. Аномалии обновления, вставки, удаления. Пример.
  3. SQL: Студенты с CITY IS NULL (ожидается Медведев, STUDENT_ID=19).
Билет №24
  1. VIEW, CTE, хранимая процедура, триггер: назначение и отличия.
  2. 1НФ, 2НФ, 3НФ. Определения и пример декомпозиции.
  3. SQL: Рекурсивный CTE: подразделения вуза UNIVERSITY_ID=10 от UNIT_ID=1.