- •Введение
- •Анализ предметной области
- •Анализ сущностей и связей между ними
- •Составление запросов к базе данных и их инкапсуляция
- •Реализация пользователей и предоставление им прав
- •Реализация триггеров
- •Реализация пользовательского интерфейса
- •Заключение
- •Список использованных источников
- •Приложение а. Скриншоты заполненных таблиц
- •Приложение б. Код для создания базы данных
- •Приложение в. Код для создания графического интерфейса
Анализ сущностей и связей между ними
Была создана ER-модель данной базы данных. Модель сущностных отношений (ER Modeling) – это графический подход к проектированию базы данных. Это модель данных высокого уровня, которая определяет элементы данных и их взаимосвязь для определенной программной системы.
В ER-модели связи делятся на три типа по множественности:
один-к-одному;
один-ко-многим;
многие-ко-многим.
Связь «один-к-одному» означает, что экземпляр одной сущности связан только с одним экземпляром другой сущности.
Связь «один-ко-многим» означает, что один экземпляр сущности, расположенный слева по связи, может быть связан с несколькими экземплярами сущности, расположенными справа по связи.
Связь «многие-ко-многим» означает, что один экземпляр первой сущности может быть связан с несколькими экземплярами второй сущности, и наоборот, один экземпляр второй сущности может быть связан с несколькими экземплярами первой сущности.
ER-модель созданной базы данных представлена на рисунке 1.
Рисунок 1 – ER-диаграмма базы данных
Скриншоты всех заполненных таблиц представлены в приложении А.
Код для создания базы данных представлен в приложении Б.
Составление запросов к базе данных и их инкапсуляция
После создания и заполнения базы данных были составлены запросы, используемые для извлечения необходимых данных из таблицы. Все запросы были инкапсулированы в хранимые процедуры MySQL.
Запрос 1. Суммарная продолжительность показа ролика определенного рекламодателя:
Алгоритм выполнения:
Объединение таблиц customers, deals, advertisements и подзапроса, получающего количество показов каждого рекламного ролика из таблицы display_schedule.
Выборка данных по указанному клиенту (customer_id).
Расчет общей продолжительности рекламных роликов как сумма произведений количества показов рекламного ролика (count) на его продолжительность (duration_minutes).
Группировка результатов по имени клиента (customer_name).
Код процедуры представлен в Листинге 1.
Результаты выполнения представлены на рисунках 2, 3.
Скриншоты использованных таблиц представлены на рисунках 4 – 7.
Листинг 1 – Процедура запроса 1
DELIMITER $$
CREATE PROCEDURE get_total_ad_duration_by_customer(IN p_customer_id INT)
BEGIN
IF p_customer_id IS NULL OR p_customer_id <= 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'ID должен быть целым неотрицательным числом';
ELSE
SELECT
c.customer_name,
SUM(ds.count * a.duration_minutes) AS total_duration_minutes
FROM
customers c
JOIN deals d ON c.customer_id = d.customer_id
JOIN advertisements a ON d.ad_id = a.ad_id
JOIN (
SELECT
ad_id,
COUNT(*) AS count
FROM
display_schedule
GROUP BY
ad_id
) ds ON a.ad_id = ds.ad_id
WHERE
c.customer_id = p_customer_id
GROUP BY
c.customer_name;
END IF;
END$$
DELIMITER ;
Рисунок 2 – Результат вызова процедуры запроса 1
Рисунок 3 – Результат выполнения запроса 1 с некорректным параметром
Рисунок 4 - Таблица customers
Рисунок 5 – Таблица deals
Рисунок 6 – Таблица advertisements
Рисунок 7 - Таблица display_schedule
Запрос 2. Фамилии агентов, которые смогли привлечь трех наиболее выгодных рекламному агентству заказчиков:
Алгоритм выполнения:
Внутренний подзапрос рассчитывает общую стоимость сделок для каждого клиента (total_value), умножая продолжительность рекламы на стоимость минуты показа.
Использует GROUP BY для группировки данных по customer_id.
Сортирует данные по total_value в порядке убывания и ограничивает результат первыми тремя клиентами с наибольшей стоимостью сделок с помощью LIMIT 3.
Основной запрос: соединяет таблицы deals, agents, и customers с результатами подзапроса, чтобы извлечь имена агентов, клиентов и общую стоимость сделок клиентов.
Использует повторное соединение для получения total_value из подзапроса.
Код процедуры представлен в Листинге 2.
Результаты выполнения представлены на рисунке 8.
Скриншоты использованных таблиц представлены на рисунках 9 – 14.
Листинг 2 – Процедура запроса 2
DELIMITER $$
CREATE PROCEDURE get_agents_top_customers()
BEGIN
-- Выбираем топ-3 клиентов по общей стоимости сделок
SELECT
a.agent_name, -- Имя агента
c.customer_name, -- Имя клиента
cds.total_value -- Общая стоимость сделок клиента
FROM
(SELECT
customer_id,
SUM(a.duration_minutes * s.cost_per_minute) AS total_value -- Вычисление общей стоимости сделок клиента
FROM
deals d
JOIN advertisements a ON d.ad_id = a.ad_id
JOIN display_schedule ds ON a.ad_id = ds.ad_id
JOIN shows s ON ds.show_id = s.show_id
GROUP BY
customer_id
ORDER BY
total_value DESC
LIMIT 3
) AS top_customers
JOIN deals d ON top_customers.customer_id = d.customer_id
JOIN agents a ON d.agent_id = a.agent_id -- Соединение с таблицей агентов
JOIN customers c ON d.customer_id = c.customer_id -- Соединение с таблицей клиентов
JOIN (
SELECT
customer_id,
SUM(a.duration_minutes * s.cost_per_minute) AS total_value
FROM
deals d
JOIN advertisements a ON d.ad_id = a.ad_id
JOIN display_schedule ds ON a.ad_id = ds.ad_id
JOIN shows s ON ds.show_id = s.show_id
GROUP BY
customer_id
) AS cds ON cds.customer_id = c.customer_id;
END$$
DELIMITER ;
Рисунок 8 – Результат вызова процедуры запроса 2
Рисунок 9 – Таблица deals
Рисунок 10 – Таблица advertisements
Рисунок 11 - Таблица display_schedule
Рисунок 12 - Таблица shows
Рисунок 13 - Таблица customers
Рисунок 14 – Таблица agents
Запрос 3. Количество рекламных роликов, которые показывают каждый будний день с 13.00 до 17.00 часов:
Алгоритм выполнения:
Фильтрация данных по будним дням и временным интервалам: WEEKDAY(ds.display_date) BETWEEN 0 AND 4 выбирает только записи, относящиеся к будним дням (понедельник - пятница), TIME(ds.display_time) BETWEEN '13:00:00' AND '17:00:00' ограничивает выборку временным интервалом с 13:00 до 17:00.
Группировка и подсчет рекламных роликов: GROUP BY DAYNAME(ds.display_date) группирует данные по названиям будних дней, COUNT(*) AS advertisements_count подсчитывает количество рекламных роликов для каждого буднего дня.
Сортировка по порядку дней недели: ORDER BY FIELD(weekday, 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday') сортирует результаты в порядке дней недели, чтобы дни отображались от понедельника до пятницы.
Код процедуры представлен в Листинге 3.
Результаты выполнения представлены на рисунке 15.
Скриншоты использованных таблиц представлены на рисунках 16, 17.
Листинг 3 – Процедура запроса 3
DELIMITER $$
CREATE PROCEDURE get_ad_count_weekday()
BEGIN
-- Выбираем количество рекламных роликов по будним дням с 13:00 до 17:00
SELECT
DAYNAME(ds.display_date) AS weekday, -- Название буднего дня
COUNT(*) AS advertisements_count -- Количество рекламных роликов
FROM
display_schedule ds
JOIN shows s ON ds.show_id = s.show_id
WHERE
WEEKDAY(ds.display_date) BETWEEN 0 AND 4 -- Будние дни (понедельник - пятница)
AND TIME(ds.display_time) BETWEEN '13:00:00' AND '17:00:00' -- Временной интервал с 13:00 до 17:00
GROUP BY
weekday -- Группировка по будним дням
ORDER BY
FIELD(weekday, 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'); -- Сортировка по порядку будних дней
END$$
DELIMITER ;
Рисунок 15 – Результат вызова процедуры запроса 3
Рисунок 16 - Таблица display_schedule
Рисунок 17 - Таблица shows
Запрос 4. Средняя зарплата агентов конкретной фирмы за последний год работы:
Алгоритм выполнения:
Объединяются таблицы deals, agents, customers, advertisements, display_schedule, и shows для получения полной информации о сделках, агентах, клиентах, рекламных роликах и показах.
WHERE c.customer_name = customer_name фильтрует записи по указанному имени клиента, передаваемому в качестве параметра процедуры.
AND d.deal_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 YEAR) AND NOW() фильтрует записи по дате, выбирая сделки, совершенные за последний год.
ROUND(AVG(a.commission_rate * (s.cost_per_minute * ad.duration_minutes)), 2) AS avg_salary вычисляет среднюю зарплату агента. Зарплата рассчитывается как произведение комиссии агента на стоимость минуты рекламы и продолжительность рекламного ролика.
Используется функция AVG() для вычисления среднего значения зарплаты агента.
SELECT customer_name, avg_salary выводит имя клиента и среднюю зарплату агента за последний год, округленную до двух десятичных знаков
Код процедуры представлен в Листинге 4.
Результаты выполнения представлены на рисунке 18.
Скриншоты использованных таблиц представлены на рисунках 19 - 24.
Листинг 4 – Процедура запроса 4
DELIMITER $$
CREATE PROCEDURE get_avg_salary_for_customer_agent(IN customer_name VARCHAR(100))
BEGIN
-- Выбираем среднюю зарплату агента для указанного клиента за последний год
SELECT
customer_name,
ROUND(AVG(a.commission_rate * (s.cost_per_minute * ad.duration_minutes)), 2) AS avg_salary
FROM
deals d
JOIN agents a ON d.agent_id = a.agent_id
JOIN customers c ON d.customer_id = c.customer_id
JOIN advertisements ad ON d.ad_id = ad.ad_id
JOIN display_schedule ds ON ad.ad_id = ds.ad_id
JOIN shows s ON ds.show_id = s.show_id
WHERE
c.customer_name = customer_name -- Имя клиента передается как параметр
AND d.deal_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 YEAR) AND NOW(); -- Выбираем сделки за последний год
END$$
DELIMITER ;
Рисунок 18 – Результат вызова процедуры запроса 4
Рисунок 19 – Таблица deals
Рисунок 20 – Таблица agents
Рисунок 21 – Таблица customers
Рисунок 22 – Таблица advertisements
Рисунок 23 – Таблица display_schedule
Рисунок 24 – Таблица shows
Запрос 5. Количество компаний–заказчиков, которые смогли оплатить показ в самых рейтинговых программах за последние 3 месяца:
Алгоритм выполнения:
Объединяются таблицы display_schedule, shows, и deals для получения информации о показах рекламы, шоу и сделках.
WHERE ds.display_date BETWEEN DATE_SUB(NOW(), INTERVAL 3 MONTH) AND NOW() фильтрует записи, выбирая данные за последние 3 месяца.
GROUP BY s.show_name, s.rating группирует данные по названию шоу и его рейтингу.
COUNT(DISTINCT d.customer_id) AS customer_count подсчитывает количество уникальных клиентов, которые заключили сделки для каждого шоу.
ORDER BY s.rating DESC сортирует результаты по убыванию рейтинга шоу.
LIMIT 10 ограничивает количество возвращаемых записей до 10.
Код процедуры представлен в Листинге 5.
Результаты выполнения представлены на рисунке 25.
Скриншоты использованных таблиц представлены на рисунках 26 - 28.
Листинг 5 – Процедура запроса 5
DELIMITER $$
CREATE PROCEDURE get_avg_salary_for_customer_agent(IN customer_name VARCHAR(100))
BEGIN
-- Выбираем среднюю зарплату агента для указанного клиента за последний год
SELECT
customer_name,
ROUND(AVG(a.commission_rate * (s.cost_per_minute * ad.duration_minutes)), 2) AS avg_salary
FROM
deals d
JOIN agents a ON d.agent_id = a.agent_id
JOIN customers c ON d.customer_id = c.customer_id
JOIN advertisements ad ON d.ad_id = ad.ad_id
JOIN display_schedule ds ON ad.ad_id = ds.ad_id
JOIN shows s ON ds.show_id = s.show_id
WHERE
c.customer_name = customer_name -- Имя клиента передается как параметр
AND d.deal_date BETWEEN DATE_SUB(NOW(), INTERVAL 1 YEAR) AND NOW(); -- Выбираем сделки за последний год
END$$
DELIMITER ;
Рисунок 25 – Результат вызова процедуры запроса 5
Рисунок 26 – Таблица display_schedule
Рисунок 27 – Таблица shows
Рисунок 28 – Таблица deals
Запрос 6. Контактное лицо от компании–заказчика, который заключил наибольшее количество договоров о рекламных кампаниях:
Алгоритм выполнения:
В подзапросе SELECT customer_id, COUNT(*) AS deal_count FROM deals GROUP BY customer_id ORDER BY deal_count DESC LIMIT 1, выполняется подсчет сделок для каждого клиента и выбирается клиент с наибольшим количеством сделок.
Результаты подзапроса объединяются с таблицей customers для получения информации о клиенте и его контактном лице.
Из объединенных данных выбираются имя контактного лица (c.contact_person), имя клиента (customer_name) и количество сделок (deal_count).
Запрос возвращает контактное лицо клиента, имя клиента и количество сделок для клиента, заключившего наибольшее количество сделок.
Код процедуры представлен в Листинге 6.
Результаты выполнения представлены на рисунке 29.
Скриншоты использованных таблиц представлены на рисунках 30, 31.
Листинг 6 – Процедура запроса 6
DELIMITER $$
CREATE PROCEDURE get_customer_with_most_deals()
BEGIN
-- Выбираем имя контактного лица клиента с наибольшим количеством сделок
SELECT
c.contact_person AS contact_name,
customer_name,
deal_count AS deal_count
-- Имя контактного лица
FROM
customers c
JOIN (
SELECT
customer_id,
COUNT(*) AS deal_count -- Количество сделок
FROM
deals
GROUP BY
customer_id
ORDER BY
deal_count DESC
LIMIT 1 -- Выбираем только одного клиента с наибольшим количеством сделок
) AS top_customer_deals ON c.customer_id = top_customer_deals.customer_id;
END$$
DELIMITER ;
Рисунок 29 – Результат вызова процедуры запроса 6
Рисунок 30 – Таблица deals
Рисунок 31 – Таблица customers
Запрос 7. Агент, совершивший минимальное количество сделок и при этом получивший наибольшие комиссионные:
Алгоритм выполнения:
В подзапросе выполняется подсчет сделок для каждого агента и вычисляется максимальная зарплата агента. Затем выбирается агент с минимальным количеством сделок и максимальной зарплатой.
Результаты подзапроса объединяются с таблицей agents для получения информации о самом удачливом агенте.
Из объединенных данных выбираются имя агента (a.agent_name), количество сделок (deal_count) и максимальная зарплата (max_salary).
Запрос возвращает имя агента, совершившего минимальное количество сделок и при этом получившего максимальную зарплату, количество его сделок и зарплату.
Код процедуры представлен в Листинге 7.
Результаты выполнения представлены на рисунке 32.
Скриншоты использованных таблиц представлены на рисунках 33 - 37.
Листинг 7 – Процедура запроса 7
DELIMITER $$
CREATE PROCEDURE get_luckiest_agent()
BEGIN
-- Выбираем имя самого удачливого агента
SELECT
a.agent_name AS lucky_agent,
deal_count,
max_salary
-- Имя агента
FROM
agents a
JOIN (
SELECT
d.agent_id,
COUNT(*) AS deal_count, -- Количество сделок
MAX(ROUND(a.commission_rate * (s.cost_per_minute * ad.duration_minutes), 2)) AS max_salary -- Максимальная зарплата
FROM
deals d
JOIN agents a ON d.agent_id = a.agent_id
JOIN advertisements ad ON d.ad_id = ad.ad_id
JOIN display_schedule ds ON ad.ad_id = ds.ad_id
JOIN shows s ON ds.show_id = s.show_id
GROUP BY
d.agent_id
ORDER BY
deal_count ASC, max_salary DESC
LIMIT 1 -- Выбираем только одного агента
) AS luckiest_agent_info ON a.agent_id = luckiest_agent_info.agent_id;
END$$
DELIMITER ;
Рисунок 32 – Результат вызова процедуры запроса 7
Рисунок 33 – Таблица deals
Рисунок 34 – Таблица agents
Рисунок 35 – Таблица advertisements
Рисунок 36 – Таблица display_schedule
Рисунок 37 – Таблица shows
Запрос 8. 5 рекламных агентств с наибольшим количеством заключенных договоров и суммарной выручкой за указанный промежуток времени:
Алгоритм выполнения:
В запросе выбираются данные о сделках и рекламе, связанные с агентами, за указанный промежуток времени (start_date до end_date). Для этого используются таблицы deals, advertisements, display_schedule и shows.
Полученные данные группируются по агентам (agent_id) с помощью GROUP BY.
Для каждого агента вычисляется количество заключенных сделок и суммарная выручка. Для этого используются функции COUNT() и SUM().
Результаты сортируются по убыванию количества сделок и суммарной выручки, чтобы определить топ-5 агентов с наибольшими показателями.
Затем используется LIMIT 5 для ограничения выборки только топ-5 агентами.
Код процедуры представлен в Листинге 8.
Результаты выполнения представлены на рисунках 38 - 43.
Скриншоты использованных таблиц представлены на рисунках .
Листинг 8 – Процедура запроса 8
DELIMITER $$
CREATE PROCEDURE get_top_agents_with_revenue(IN start_date DATE, IN end_date DATE)
BEGIN
-- Выбираем топ-5 агентов с наибольшим количеством заключенных договоров и суммарной выручкой за указанный промежуток времени
SELECT
a.agent_name, -- Имя агента
COUNT(d.deal_id) AS deal_count, -- Количество заключенных договоров
ROUND(SUM(a.commission_rate * (s.cost_per_minute * ad.duration_minutes))) AS total_revenue -- Суммарная выручка
FROM
agents a
LEFT JOIN deals d ON a.agent_id = d.agent_id
LEFT JOIN advertisements ad ON d.ad_id = ad.ad_id
LEFT JOIN display_schedule ds ON ad.ad_id = ds.ad_id
LEFT JOIN shows s ON ds.show_id = s.show_id
WHERE
d.deal_date BETWEEN start_date AND end_date -- Заданный промежуток времени
GROUP BY
a.agent_id
ORDER BY
deal_count DESC, total_revenue DESC -- Сортировка по количеству договоров и суммарной выручке
LIMIT 5; -- Ограничение до топ-5 агентов
END$$
DELIMITER ;
Рисунок 38 – Результат вызова процедуры запроса 8
Рисунок 39 – Таблица deals
Рисунок 40 – Таблица agents
Рисунок 41 – Таблица advertisements
Рисунок 42 – Таблица display_schedule
Рисунок 43 – Таблица shows
Запрос 9. Средняя продолжительность рекламы в передачах с рейтингом, выше указанного:
Алгоритм выполнения:
Выполняется запрос, который выбирает среднюю продолжительность рекламы (average_ad_duration) и количество рекламных роликов (ad_count) для передач с рейтингом выше указанного порога (rating_threshold). Для этого используются таблицы advertisements, display_schedule и shows, где рейтинг передачи выше порогового значения.
Результаты запроса содержат среднюю продолжительность рекламы и количество рекламных роликов для передач с высоким рейтингом.
Код процедуры представлен в Листинге 9.
Результаты выполнения представлены на рисунках 44, 45.
Скриншоты использованных таблиц представлены на рисунках 46 - 48.
Листинг 9 – Процедура запроса 9
DELIMITER $$
CREATE PROCEDURE get_ad_info_for_high_rating_shows(IN rating_threshold FLOAT)
BEGIN
IF rating_threshold > 10 OR rating_threshold < 0 OR rating_threshold IS NULL THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Введите рейтинг от 0 до 10';
ELSE
-- Вычисляем среднюю продолжительность и количество рекламы в передачах с рейтингом выше указанного
SELECT
ROUND(AVG(a.duration_minutes), 2) AS average_ad_duration, -- Средняя продолжительность рекламы
COUNT(*) AS ad_count -- Количество реклам
FROM
advertisements a
JOIN display_schedule ds ON a.ad_id = ds.ad_id
JOIN shows s ON ds.show_id = s.show_id
WHERE
s.rating > rating_threshold; -- Рейтинг выше указанного порога
END IF;
END$$
DELIMITER ;
Рисунок 44 – Результат вызова процедуры запроса 9
Рисунок 45 – Результат вызова процедуры запроса 9 с некорректным параметром
Рисунок 46 – Таблица advertisements
Рисунок 47 – Таблица display_schedule
Рисунок 48 – Таблица shows
Запрос 10. 5 передач, реклама в которых стоила больше всего денег за указанный промежуток времени:
Алгоритм выполнения:
Запрос выбирает информацию о шоу (show_name) и суммарную стоимость рекламы (total_revenue) для каждого шоу за указанный период времени. Используются таблицы display_schedule, shows и advertisements.
Выбираются записи из таблицы display_schedule, которые попадают в указанный временной диапазон start_date и end_date.
Данные группируются по идентификатору шоу (show_id), чтобы рассчитать суммарную стоимость рекламы для каждого шоу.
Результаты сортируются по убыванию суммарной стоимости рекламы, чтобы определить наиболее прибыльные шоу.
Выборка ограничивается пятью наиболее прибыльными шоу, используя оператор LIMIT 5.
Код процедуры представлен в Листинге 10.
Результаты выполнения представлены на рисунке 49.
Скриншоты использованных таблиц представлены на рисунках 50 - 52.
Листинг 10 – Процедура запроса 10
DELIMITER $$
CREATE PROCEDURE get_most_profitable_show(IN start_date DATE, IN end_date DATE)
BEGIN
-- Находим шоу, в котором реклама стоила больше всего за указанный период
SELECT
s.show_name, -- Название шоу
SUM(a.duration_minutes * s.cost_per_minute) AS total_revenue -- Суммарная стоимость рекламы
FROM
display_schedule ds
JOIN shows s ON ds.show_id = s.show_id
JOIN advertisements a ON ds.ad_id = a.ad_id
WHERE
ds.display_date BETWEEN start_date AND end_date -- Указанный период
GROUP BY
s.show_id
ORDER BY
total_revenue DESC
LIMIT 5; -- Выбираем только 5 шоу с максимальной суммарной стоимостью рекламы
END$$
DELIMITER ;
Рисунок 49 – Результат вызова процедуры запроса 10
Рисунок 50 – Таблица display_schedule
Рисунок 51 – Таблица shows
Рисунок 52 – Таблица advertisements
