759 lines
41 KiB
Typst
759 lines
41 KiB
Typst
#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-запросы применяются для анализа и обработки информации в реальных базах данных.
|
||
|
||
|
||
|