#show link: underline #set text(size: 1.3em) #set page( header: context { if counter(page).get().first() == 1 [ #align(center)[ Санкт-Петербургский национальный исследовательский университет информационных технологий, механики и оптики ] ] }, footer: context { if counter(page).get().first() == 1 [ #align(center)[Санкт-Петербург \ 2025] ] else [ #align(center)[#counter(page).display("1")] ] } ) #show raw.where(block: false): box.with( fill: luma(240), inset: (x: 3pt, y: 0pt), outset: (y: 3pt), radius: 2pt, ) #show raw.where(block: true): block.with( fill: luma(240), inset: 10pt, radius: 4pt, ) // title \ \ \ #align(center)[Факультет инфокоммуникационных технологий] #align(center)[Направление подготовки 11.03.02] \ \ #align(center)[Практическая работа №3] //#align(center)[Установка и первоначальная настройка субд postgresql.] \ \ \ \ //#align(center)[Вариант 19] \ \ \ \ \ \ \ #align(right)[Выполнил:] #align(right)[Дощенников Никита Андреевич] #align(right)[Группа: К3221] #align(right)[Проверила:] #align(right)[Татьяна Евгеньевна Войтюк] #pagebreak() === Цель работы Целью данной работы является изучение основных операций с базами данных на примере postgresql. В ходе работы мы учимся выполнять различные виды соединений таблиц, использовать агрегатные функции, группировать данные и получать сводную информацию о сотрудниках и отделах. Всё это позволяет лучше понять, как организуются данные в реальных информационных системах и как из них можно получать нужную информацию. === Задачи, решаемые при выполнении работы В рамках работы необходимо выполнить несколько типов заданий. Сначала мы работаем с объединением таблиц, чтобы научиться получать информацию о сотрудниках, их отделах, руководителях и коллегах. Затем изучаем групповые функции, которые позволяют подсчитать количество сотрудников, средние и максимальные зарплаты, разницу окладов и другие показатели. Также нужно уметь фильтровать данные по различным условиям, сортировать результаты и использовать агрегирование, чтобы формировать отчёты по отделам и должностям. === Исходные данные Для выполнения работы использовалась база данных, содержащая таблицы с информацией о сотрудниках, отделах, местоположениях, странах и регионах. Таблицы включают такие поля, как имя, фамилия, идентификатор сотрудника, должность, зарплата, бонус, дата найма, идентификатор отдела и руководителя. Эти данные позволяют выполнять все необходимые запросы: соединять таблицы, группировать и фильтровать информацию, а также анализировать структуру и показатели работы сотрудников и отделов. === Выполнение работы // формирование запроса, краткое описание используемых конструкций/функций при необходимости. Предоставляется возможность дополнить отчет скриншотами результатов. ==== Задание 1. Использование объединения таблиц ===== 1.1 *Напишите запрос для вывода фамилии, имени, названия отдела для всех работников, в фамилии которых есть буква «u» (в строчном регистре). Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT e."LAST_NAME", e."FIRST_NAME", d."DEPARTMENT_NAME" FROM "EmployeesDepartments"."EMPLOYEES" e JOIN "EmployeesDepartments"."DEPARTMENTS" d ON e."DEPARTMENT_ID" = d."DEPARTMENT_ID" WHERE e."LAST_NAME" LIKE '%u%'; ``` - Соединяем таблицы `EMPLOYEES` и `DEPARTMENTS` по `DEPARTMENT_ID` с помощью `INNER JOIN`. - Выбираем фамилию, имя и название отдела. - Фильтруем только тех сотрудников, у которых фамилия содержит букву «u». #align(center)[ #figure( image("assets/1.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.1] ) ] ===== 1.2 *Напишите запрос для вывода имени, фамилии, названия должности и названия отдела для всех работников. Отсортируйте результат по идентификатору работника. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT e."FIRST_NAME", e."LAST_NAME", e."JOB_ID", d."DEPARTMENT_NAME" FROM "EmployeesDepartments"."EMPLOYEES" e JOIN "EmployeesDepartments"."DEPARTMENTS" d ON e."DEPARTMENT_ID" = d."DEPARTMENT_ID" ORDER BY e."EMPLOYEE_ID"; ``` - Соединяем `EMPLOYEES` и `DEPARTMENTS` по `DEPARTMENT_ID` через `INNER JOIN`. - Выбираем имя, фамилию, должность и отдел сотрудника. - Сортируем по `EMPLOYEE_ID` для просмотра всех сотрудников по порядку. #align(center)[ #figure( image("assets/2.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.2] ) ] ===== 1.3 *Напишите запрос для вывода названия отдела, фамилии и имени сотрудника для всех сотрудников, у которых есть бонус, работающих в 80-ом и 85-ом отделах. Полученный результат отсортируйте по номеру отдела, размеру бонуса по убыванию, а затем фамилии. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT d."DEPARTMENT_NAME", e."LAST_NAME", e."FIRST_NAME", e."COMMISSION_PCT" AS "Bonus" FROM "EmployeesDepartments"."EMPLOYEES" e JOIN "EmployeesDepartments"."DEPARTMENTS" d ON e."DEPARTMENT_ID" = d."DEPARTMENT_ID" WHERE e."COMMISSION_PCT" IS NOT NULL AND e."DEPARTMENT_ID" IN (80, 85) ORDER BY e."DEPARTMENT_ID", e."COMMISSION_PCT" DESC, e."LAST_NAME"; ``` - Выбираем сотрудников из отделов 80 и 85 с ненулевым бонусом. - Соединяем таблицы сотрудников и отделов через `INNER JOIN`. - Сортируем по номер отдела, бонус по убыванию, фамилия. - В результате видны только сотрудники с бонусом и существующим отделом. #align(center)[ #figure( image("assets/3.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.3] ) ] ===== 1.4 *Напишите запрос для вывода фамилии, имени, названия страны и региона для всех работников, работающих в Северной Америке. Отсортируйте результат по названию страны и фамилии сотрудника. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT e."LAST_NAME", e."FIRST_NAME", c."COUNTRY_NAME", r."REGION_NAME" FROM "EmployeesDepartments"."EMPLOYEES" e JOIN "EmployeesDepartments"."DEPARTMENTS" d ON e."DEPARTMENT_ID" = d."DEPARTMENT_ID" JOIN "EmployeesDepartments"."LOCATIONS" l ON d."LOCATION_ID" = l."LOCATION_ID" JOIN "Countries"."COUNTRIES" c ON l."COUNTRY_ID" = c."COUNTRY_ID" JOIN "Countries"."REGIONS" r ON c."REGION_ID" = r."REGION_ID" WHERE r."REGION_NAME" = 'Americas' ORDER BY c."COUNTRY_NAME", e."LAST_NAME"; ``` - Соединяем сотрудников, отделы, локации, страны, регионы - Используем `INNER JOIN` - Фильтруем регион `Americas` - Сортируем по стране и фамилии сотрудника #align(center)[ #figure( image("assets/4.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.4] ) ] ===== 1.5 *Напишите запрос для вывода фамилии и идентификатора работника, а также фамилии и идентификатора его начальника. Назовите столбцы результата «Подчиненный», «Идентификатор работника», «Руководитель», «Идентификатор руководителя». Отсортируйте результат по идентификатору руководителя по возрастанию и по идентификатору работника по убыванию. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT e."LAST_NAME" AS "Подчиненный", e."EMPLOYEE_ID" AS "Идентификатор работника", m."LAST_NAME" AS "Руководитель", m."EMPLOYEE_ID" AS "Идентификатор руководителя" FROM "EmployeesDepartments"."EMPLOYEES" e LEFT JOIN "EmployeesDepartments"."EMPLOYEES" m ON e."MANAGER_ID" = m."EMPLOYEE_ID" ORDER BY m."EMPLOYEE_ID" ASC, e."EMPLOYEE_ID" DESC; ``` - Используется `LEFT JOIN`, чтобы включить всех сотрудников, даже если у них нет начальника. - Сортировка сначала по ID менеджера, потом по ID сотрудника. #align(center)[ #figure( image("assets/5.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.5] ) ] ===== 1.6 *Измените запрос из пункта 1.5. таким образом, чтобы получить фамилии всех работников в столбце «Подчиненный», включая Кинга, который не имеет руководителя. Отсортируйте результат по идентификатору подчиненного, укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT e."LAST_NAME" AS "Подчиненный", e."EMPLOYEE_ID" AS "Идентификатор подчиненного", m."LAST_NAME" AS "Руководитель", m."EMPLOYEE_ID" AS "Идентификатор руководителя" FROM "EmployeesDepartments"."EMPLOYEES" e LEFT JOIN "EmployeesDepartments"."EMPLOYEES" m ON e."MANAGER_ID" = m."EMPLOYEE_ID" ORDER BY e."EMPLOYEE_ID"; ``` - Используем `LEFT JOIN` таблицы `EMPLOYEES`, чтобы получить и менеджеров, и всех подчинённых, включая тех, у кого нет руководителя. - Сортировка выполняется по ID подчинённого для удобного просмотра. #align(center)[ #figure( image("assets/6.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.6] ) ] ===== 1.7 *Напишите запрос для вывода названия отдела, фамилии сотрудника и фамилий всех его коллег для сотрудников Fay, Hartstein и Davies. Назовите столбцы результата «Отдел», «Работник», «Коллеги». Отсортируйте результат по отделу и фамилии сотрудника. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT d."DEPARTMENT_NAME" AS "Отдел", e1."LAST_NAME" AS "Работник", STRING_AGG(e2."LAST_NAME", ', ') AS "Коллеги" FROM "EmployeesDepartments"."EMPLOYEES" e1 JOIN "EmployeesDepartments"."DEPARTMENTS" d ON e1."DEPARTMENT_ID" = d."DEPARTMENT_ID" JOIN "EmployeesDepartments"."EMPLOYEES" e2 ON e1."DEPARTMENT_ID" = e2."DEPARTMENT_ID" AND e1."EMPLOYEE_ID" <> e2."EMPLOYEE_ID" WHERE e1."LAST_NAME" IN ('Fay', 'Hartstein', 'Davies') GROUP BY d."DEPARTMENT_NAME", e1."LAST_NAME" ORDER BY d."DEPARTMENT_NAME", e1."LAST_NAME"; ``` - Используем `JOIN`, чтобы найти коллег по одному отделу, исключая самого сотрудника. - Применяем `STRING_AGG` для объединения всех фамилий коллег в одну строку. - Фильтруем только выбранных сотрудников и сортируем результат по отделу и фамилии. #align(center)[ #figure( image("assets/7.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.7] ) ] ===== 1.8 *Напишите запрос для вывода всех категорий работников (GRADE_LEVEL), их фамилий, размеров оклада, названий должностей и названий отделов. Если в некоторой категории нет работников, то эта категория всё равно должна присутствовать в результате. Отсортируйте результат по категории работника, отделу и фамилии. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT jg."GRADE_LEVEL" AS "Категория", e."LAST_NAME" AS "Фамилия", e."SALARY" AS "Оклад", e."JOB_ID" AS "Должность", d."DEPARTMENT_NAME" AS "Отдел" FROM "EmployeesDepartments"."JOB_GRADES" jg LEFT JOIN "EmployeesDepartments"."EMPLOYEES" e ON e."SALARY" BETWEEN jg."LOWEST_SAL" AND jg."HIGHEST_SAL" LEFT JOIN "EmployeesDepartments"."DEPARTMENTS" d ON e."DEPARTMENT_ID" = d."DEPARTMENT_ID" ORDER BY jg."GRADE_LEVEL", d."DEPARTMENT_NAME", e."LAST_NAME"; ``` - Основная таблица — `JOB_GRADES`. - Сотрудники и отделы присоединяются через `LEFT JOIN`. - Таким образом, категории без работников всё равно будут отображаться. - Результат отсортирован по категории, отдел, фамилия. #align(center)[ #figure( image("assets/8.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.8] ) ] ===== 1.9 *Напишите запрос для вывода фамилий и дат найма всех сотрудников, а также фамилий и дат найма их руководителей, для всех сотрудников, руководители которых устроились на работу в 2008ом году, но при это сами подчиненные устроились на работу до 2008 года. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT e."LAST_NAME" AS "Сотрудник", e."HIRE_DATE" AS "Дата найма сотрудника", m."LAST_NAME" AS "Руководитель", m."HIRE_DATE" AS "Дата найма руководителя" FROM "EmployeesDepartments"."EMPLOYEES" e JOIN "EmployeesDepartments"."EMPLOYEES" m ON e."MANAGER_ID" = m."EMPLOYEE_ID" WHERE EXTRACT(YEAR FROM m."HIRE_DATE") = 2008 AND EXTRACT(YEAR FROM e."HIRE_DATE") < 2008 ORDER BY m."LAST_NAME", e."LAST_NAME"; ``` - Соединяем сотрудников с их руководителями `JOIN`. - Фильтруем по дате найма: подчинённый до 2008, руководитель — 2008. #align(center)[ #figure( image("assets/9.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.9] ) ] ===== 1.10 *Для всех работников, менеджеры которых устроились на работу в январе, и длина названий должностей этих работников(подчиненных) более 15ти символов, сформируйте запрос для вывода названия должности, фамилии работника, даты найма, фамилии руководителя и его даты найма. Результат отсортировать по названию должности, фамилии руководителя, идентификатору работника. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT e."JOB_ID" AS "Должность", e."LAST_NAME" AS "Сотрудник", e."HIRE_DATE" AS "Дата найма сотрудника", m."LAST_NAME" AS "Руководитель", m."HIRE_DATE" AS "Дата найма руководителя" FROM "EmployeesDepartments"."EMPLOYEES" e JOIN "EmployeesDepartments"."EMPLOYEES" m ON e."MANAGER_ID" = m."EMPLOYEE_ID" WHERE EXTRACT(MONTH FROM m."HIRE_DATE") = 1 AND LENGTH(e."JOB_ID") > 15 ORDER BY e."JOB_ID", m."LAST_NAME", e."EMPLOYEE_ID"; ``` - Соединяем сотрудников с их менеджерами `JOIN`. - Фильтруем менеджеров, нанятых в январе, и подчинённых с длинной должностью > 15 символов. - Сортировка по должности, фамилия руководителя, ID сотрудника. #align(center)[ #figure( image("assets/10.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.10] ) ] ===== 1.11 *Напишите запрос для вывода идентификатора отдела и его названия для всех отделов, в которых нет работников. Укажите, какой тип соединения таблиц используется в данном запросе, и задокументируйте результат его выполнения.* ```sql SELECT d."DEPARTMENT_ID", d."DEPARTMENT_NAME" FROM "EmployeesDepartments"."DEPARTMENTS" d LEFT JOIN "EmployeesDepartments"."EMPLOYEES" e ON d."DEPARTMENT_ID" = e."DEPARTMENT_ID" WHERE e."EMPLOYEE_ID" IS NULL ORDER BY d."DEPARTMENT_ID"; ``` - Используется `LEFT JOIN` для включения всех отделов. - Отбираем только те отделы, где нет сотрудников. - Сортируем результат по ID отдела. #align(center)[ #figure( image("assets/11.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 1.11] ) ] ==== Задание 2. Использование групповых функций ===== 2.1 *Напишите запрос для вывода идентификатора отдела, количества работников в нём, минимальной, максимальной и средней заработной платы по отделу, а также дат первого и последнего приёма в отдел. Для всех столбцов результата задайте понятные наименования и отсортируйте результат по количеству сотрудников (по убыванию). Задокументируйте результат выполнения запроса.* ```sql SELECT d."DEPARTMENT_ID" AS "ID отдела", COUNT(e."EMPLOYEE_ID") AS "Количество сотрудников", MIN(e."SALARY") AS "Минимальная зарплата", MAX(e."SALARY") AS "Максимальная зарплата", ROUND(AVG(e."SALARY"), 2) AS "Средняя зарплата", MIN(e."HIRE_DATE") AS "Дата первого приема", MAX(e."HIRE_DATE") AS "Дата последнего приема" FROM "EmployeesDepartments"."DEPARTMENTS" d LEFT JOIN "EmployeesDepartments"."EMPLOYEES" e ON d."DEPARTMENT_ID" = e."DEPARTMENT_ID" GROUP BY d."DEPARTMENT_ID" ORDER BY "Количество сотрудников" DESC; ``` - Используем `LEFT JOIN` для включения всех отделов. - Считаем количество сотрудников, минимальные/максимальные/средние зарплаты и даты первого/последнего приема. - Сортируем результат по количеству сотрудников в отделе по убыванию. #align(center)[ #figure( image("assets/12.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.1] ) ] ===== 2.2 *Напишите запрос для вывода названия должности, самого низкого, самого высокого и среднего оклада по ней, а также суммы окладов по каждой должности. Отсортируйте результат по названию должности и задокументируйте результат выполнения запроса.* ```sql SELECT e."JOB_ID" AS "Должность", MIN(e."SALARY") AS "Минимальный оклад", MAX(e."SALARY") AS "Максимальный оклад", ROUND(AVG(e."SALARY"), 2) AS "Средний оклад", SUM(e."SALARY") AS "Сумма окладов" FROM "EmployeesDepartments"."EMPLOYEES" e GROUP BY e."JOB_ID" ORDER BY e."JOB_ID"; ``` - Используем агрегатные функции для вычисления минимального, максимального, среднего и суммарного оклада по каждой должности. - Группируем сотрудников по `JOB_ID`. - Сортировка выполняется по названию должности. #align(center)[ #figure( image("assets/13.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.2] ) ] ===== 2.3 *Напишите запрос, который позволяет получить список отделов (идентификаторов отделов), их наименований и округленную среднюю заработную плату работников в каждом из них. Для всех столбцов результата задайте понятные наименования, отсортируйте по округленной средней заработной плате и задокументируйте результат выполнения запроса.* ```sql SELECT d."DEPARTMENT_ID" AS "ID отдела", d."DEPARTMENT_NAME" AS "Название отдела", ROUND(AVG(e."SALARY"), 2) AS "Средняя зарплата" FROM "EmployeesDepartments"."DEPARTMENTS" d LEFT JOIN "EmployeesDepartments"."EMPLOYEES" e ON d."DEPARTMENT_ID" = e."DEPARTMENT_ID" GROUP BY d."DEPARTMENT_ID", d."DEPARTMENT_NAME" ORDER BY "Средняя зарплата"; ``` - Используем `LEFT JOIN` для включения всех отделов. - Средняя зарплата вычисляется функцией `AVG` и округляется через `ROUND`. - Сортируем результат по средней зарплате. #align(center)[ #figure( image("assets/14.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.3] ) ] ===== 2.4 *Напишите запрос, который позволяет получить список руководителей (их имя, фамилию, должность), у которых количество подчиненных больше 5 и сумма всех зарплат его подчиненных больше 50000. Задокументируйте результат выполнения запроса.* ```sql SELECT m."FIRST_NAME" AS "Имя", m."LAST_NAME" AS "Фамилия", m."JOB_ID" AS "Должность", COUNT(e."EMPLOYEE_ID") AS "Количество подчинённых", SUM(e."SALARY") AS "Сумма зарплат подчинённых" FROM "EmployeesDepartments"."EMPLOYEES" m JOIN "EmployeesDepartments"."EMPLOYEES" e ON e."MANAGER_ID" = m."EMPLOYEE_ID" GROUP BY m."EMPLOYEE_ID", m."FIRST_NAME", m."LAST_NAME", m."JOB_ID" HAVING COUNT(e."EMPLOYEE_ID") > 5 AND SUM(e."SALARY") > 50000 ORDER BY "Количество подчинённых" DESC; ``` - `JOIN` позволяет сопоставить руководителя с его подчинёнными. - Используем `COUNT` и `SUM` для подсчёта и суммы зарплат. - `HAVING` фильтрует руководителей по заданным критериям. #align(center)[ #figure( image("assets/15.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.4] ) ] ===== 2.5 *Напишите запрос для вывода идентификатора отдела и разности между самым высоким и самым низким окладами по каждому отделу. Результат отсортируйте по убыванию разности окладов.* ```sql SELECT e."DEPARTMENT_ID" AS "ID отдела", (MAX(e."SALARY") - MIN(e."SALARY")) AS "Разница окладов" FROM "EmployeesDepartments"."EMPLOYEES" e GROUP BY e."DEPARTMENT_ID" ORDER BY "Разница окладов" DESC; ``` - Используем `MAX` и `MIN` для вычисления диапазона зарплат в каждом отделе. - Группировка по отделу позволяет рассчитать разницу окладов на уровне каждого отдела. - Сортируем результат по убыванию разницы. #align(center)[ #figure( image("assets/16.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.5] ) ] ===== 2.6 *Напишите запрос для вывода идентификатора каждого руководителя, имеющего подчинённых, и средней заработной платы этих подчинённых, но только для тех руководителей, которые не получают бонусов, и у которых средняя заработная плата подчинённых находится в диапазоне от 6000 до 9000. Отсортируйте результат по идентификатору руководителя и задокументируйте результат выполнения запроса.* ```sql SELECT m."EMPLOYEE_ID" AS "ID руководителя", ROUND(AVG(e."SALARY"), 2) AS "Средняя зарплата подчинённых" FROM "EmployeesDepartments"."EMPLOYEES" m JOIN "EmployeesDepartments"."EMPLOYEES" e ON e."MANAGER_ID" = m."EMPLOYEE_ID" WHERE m."COMMISSION_PCT" IS NULL GROUP BY m."EMPLOYEE_ID" HAVING AVG(e."SALARY") BETWEEN 6000 AND 9000 ORDER BY m."EMPLOYEE_ID"; ``` - `Self JOIN` позволяет сопоставить руководителя с его подчинёнными. - Фильтруем руководителей без бонуса и подбираем только тех, у кого средняя зарплата подчинённых в заданном диапазоне. #align(center)[ #figure( image("assets/17.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.6] ) ] ===== 2.7 *Напишите запрос для вывода названия отдела, местоположения отдела (город, адрес) и количества служащих в нём, но только для тех отделов, в которых работники занимают различные должности. Для всех столбцов результата задайте понятные наименования и отсортируйте результат по количеству служащих (по убыванию). Результат выполнения запроса задокументируйте.* ```sql SELECT d."DEPARTMENT_NAME" AS "Отдел", l."CITY" || ', ' || l."STREET_ADDRESS" AS "Местоположение", COUNT(e."EMPLOYEE_ID") AS "Количество сотрудников" FROM "EmployeesDepartments"."DEPARTMENTS" d JOIN "EmployeesDepartments"."EMPLOYEES" e ON d."DEPARTMENT_ID" = e."DEPARTMENT_ID" JOIN "EmployeesDepartments"."LOCATIONS" l ON d."LOCATION_ID" = l."LOCATION_ID" GROUP BY d."DEPARTMENT_NAME", l."CITY", l."STREET_ADDRESS", d."DEPARTMENT_ID" HAVING COUNT(DISTINCT e."JOB_ID") > 1 ORDER BY "Количество сотрудников" DESC; ``` - Соединяем отделы с сотрудниками и местоположениями `INNER JOIN`. - Считаем количество сотрудников и проверяем, что в отделе есть различные должности. #align(center)[ #figure( image("assets/18.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.7] ) ] ===== 2.8 *Напишите запрос для вывода года и количества принятых на работу сотрудников в указанном году по всем годам. Результат отсортировать по количеству принятых на работу сотрудников в год и задокументировать.* ```sql SELECT EXTRACT(YEAR FROM e."HIRE_DATE") AS "Год", COUNT(e."EMPLOYEE_ID") AS "Количество принятых" FROM "EmployeesDepartments"."EMPLOYEES" e GROUP BY EXTRACT(YEAR FROM e."HIRE_DATE") ORDER BY "Количество принятых" DESC; ``` - Извлекаем год найма с помощью `EXTRACT(YEAR ...)`. - Считаем количество сотрудников, принятых в каждый год `COUNT`. - Сортируем по количеству принятых сотрудников по убыванию. #align(center)[ #figure( image("assets/19.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.8] ) ] ===== 2.9 *Напишите запрос, который выводит длину имени и количество сотрудников с соответствующей длиной имени. В результат включите только тех сотрудников, у которых длина имени больше 5, а количество сотрудников с такой длиной — больше 3. Результат отсортируйте по длине имени и задокументируйте.* ```sql SELECT LENGTH(e."FIRST_NAME") AS "Длина имени", COUNT(e."EMPLOYEE_ID") AS "Количество сотрудников" FROM "EmployeesDepartments"."EMPLOYEES" e WHERE LENGTH(e."FIRST_NAME") > 5 GROUP BY LENGTH(e."FIRST_NAME") HAVING COUNT(e."EMPLOYEE_ID") > 3 ORDER BY "Длина имени"; ``` - Считаем количество сотрудников по длине имени `LENGTH + COUNT`. - Отбираем только имена длиннее 5 символов и длины, встречающиеся у более чем 3 сотрудников. - Сортируем результат по длине имени. #align(center)[ #figure( image("assets/20.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.9] ) ] ===== 2.10 *Напишите запрос, который выводит названия отделов, их идентификационный номер, адрес и город, а также количество работников в каждом отделе, включая те, где пока нет ни одного работника. Укажите, какой тип соединения таблиц используется в данном запросе. Для всех столбцов результата задайте понятные наименования, отсортируйте по номеру отдела и задокументируйте.* ```sql SELECT d."DEPARTMENT_NAME" AS "Название отдела", d."DEPARTMENT_ID" AS "ID отдела", l."STREET_ADDRESS" AS "Адрес", l."CITY" AS "Город", COUNT(e."EMPLOYEE_ID") AS "Количество сотрудников" FROM "EmployeesDepartments"."DEPARTMENTS" d LEFT JOIN "EmployeesDepartments"."EMPLOYEES" e ON d."DEPARTMENT_ID" = e."DEPARTMENT_ID" JOIN "EmployeesDepartments"."LOCATIONS" l ON d."LOCATION_ID" = l."LOCATION_ID" GROUP BY d."DEPARTMENT_ID", d."DEPARTMENT_NAME", l."STREET_ADDRESS", l."CITY" ORDER BY d."DEPARTMENT_ID"; ``` - Считаем количество сотрудников в каждом отделе, включая отделы без сотрудников `LEFT JOIN`. - Получаем адрес и город через соединение с `LOCATIONS`. - Результат отсортирован по номеру отдела. #align(center)[ #figure( image("assets/21.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.10] ) ] ===== 2.11 *Напишите запрос, который выводит название должности, количество работников, занимающих эту должность, а также среднюю заработную плату по каждой должности в отделах Administration и IT. В результат включите только те должности, где средняя зарплата превышает 4000, и на которых работает более двух сотрудников. Для всех столбцов результата задайте понятные наименования, отсортируйте данные по убыванию количества сотрудников и задокументируйте.* ```sql SELECT e."JOB_ID" AS "Должность", COUNT(e."EMPLOYEE_ID") AS "Количество сотрудников", ROUND(AVG(e."SALARY"), 2) AS "Средняя зарплата" FROM "EmployeesDepartments"."EMPLOYEES" e JOIN "EmployeesDepartments"."DEPARTMENTS" d ON e."DEPARTMENT_ID" = d."DEPARTMENT_ID" WHERE d."DEPARTMENT_NAME" IN ('Administration', 'IT') GROUP BY e."JOB_ID" HAVING COUNT(e."EMPLOYEE_ID") > 2 AND AVG(e."SALARY") > 4000 ORDER BY "Количество сотрудников" DESC; ``` - Соединяем таблицы сотрудников и отделов. - Фильтруем только нужные отделы. - Группируем по должности и считаем количество сотрудников и среднюю зарплату. - Фильтруем по условиям `HAVING` и сортируем результат по количеству сотрудников. #align(center)[ #figure( image("assets/22.png"), supplement: [Рис.], caption: [Результат выполнения запроса задания 2.11] ) ] === Выводы и анализ результатов работы // Обобщение результатов выполнения всех задач работы: что должны были достичь, что фактически достигли и каким образом, с какими трудностями столкнулись, какие проблемы на каких этапах выполнения возникли и как именно были решены. В ходе выполнения работы удалось последовательно отработать ключевые навыки работы с реляционными базами данных. Основной целью было научиться применять различные виды соединений таблиц, фильтрацию, группировку, агрегирование и оформление результатов. Все эти задачи были выполнены: мы строили запросы с `INNER JOIN`, исследовали структуру связанных таблиц, получали данные о сотрудниках и отделах, вычисляли агрегаты и формировали отчёты, соответствующие условиям заданий. Удалось добиться полного понимания, как извлекать данные из нескольких таблиц и объединять их в единую осмысленную выборку. Отдельные задания требовали работы с условиями, правильного выбора типа соединения и обращения к именованным полям. В итоге была закреплена практика использования агрегатных функций, фильтрации по шаблону, сортировки результатов. Работа показала, как шаг за шагом строится аналитика поверх обычных данных, и позволила сформировать цельное понимание того, как sql-запросы применяются для анализа и обработки информации в реальных базах данных.