diff --git a/labs/lab2/assets/20.png b/labs/lab2/assets/20.png new file mode 100644 index 0000000..9ae44bd Binary files /dev/null and b/labs/lab2/assets/20.png differ diff --git a/labs/lab2/assets/21.png b/labs/lab2/assets/21.png new file mode 100644 index 0000000..77a21b9 Binary files /dev/null and b/labs/lab2/assets/21.png differ diff --git a/labs/lab2/assets/22.png b/labs/lab2/assets/22.png new file mode 100644 index 0000000..fc55363 Binary files /dev/null and b/labs/lab2/assets/22.png differ diff --git a/labs/lab2/assets/23.png b/labs/lab2/assets/23.png new file mode 100644 index 0000000..d399ddd Binary files /dev/null and b/labs/lab2/assets/23.png differ diff --git a/labs/lab2/assets/24.png b/labs/lab2/assets/24.png new file mode 100644 index 0000000..2e4f5eb Binary files /dev/null and b/labs/lab2/assets/24.png differ diff --git a/labs/lab2/assets/25.png b/labs/lab2/assets/25.png new file mode 100644 index 0000000..9bda08f Binary files /dev/null and b/labs/lab2/assets/25.png differ diff --git a/labs/lab2/assets/26.png b/labs/lab2/assets/26.png new file mode 100644 index 0000000..5380804 Binary files /dev/null and b/labs/lab2/assets/26.png differ diff --git a/labs/lab2/assets/27.png b/labs/lab2/assets/27.png new file mode 100644 index 0000000..12c3cf2 Binary files /dev/null and b/labs/lab2/assets/27.png differ diff --git a/labs/lab2/assets/28.png b/labs/lab2/assets/28.png new file mode 100644 index 0000000..1423d96 Binary files /dev/null and b/labs/lab2/assets/28.png differ diff --git a/labs/lab2/assets/29.png b/labs/lab2/assets/29.png new file mode 100644 index 0000000..6e04654 Binary files /dev/null and b/labs/lab2/assets/29.png differ diff --git a/labs/lab2/assets/30.png b/labs/lab2/assets/30.png new file mode 100644 index 0000000..1df692f Binary files /dev/null and b/labs/lab2/assets/30.png differ diff --git a/labs/lab2/report.pdf b/labs/lab2/report.pdf index 1369a83..db4a250 100644 Binary files a/labs/lab2/report.pdf and b/labs/lab2/report.pdf differ diff --git a/labs/lab2/report.typ b/labs/lab2/report.typ index 5c493b5..5264ac4 100644 --- a/labs/lab2/report.typ +++ b/labs/lab2/report.typ @@ -64,10 +64,92 @@ === Цель работы +Изучение и практическое освоение основных конструкций языка SQL для работы с реляционными базами данных, включая: + +- Формирование запросов на выборку данных с использованием оператора `SELECT` + +- Применение предложений `WHERE` и `ORDER BY` для фильтрации и сортировки данных + +- Использование встроенных функций SQL для обработки числовых, символьных данных и дат + +- Работу с условными выражениями для формирования вычисляемых полей + +- Получение навыков создания сложных запросов с применением различных операторов и функций SQL + + === Задачи, решаемые при выполнении работы +- Освоить базовые операции с таблицами: + - Изучить структуру таблиц базы данных + - Выполнить выборку данных из таблиц с использованием оператора SELECT + - Научиться задавать псевдонимы для столбцов + - Освоить сортировку данных с помощью предложения ORDER BY + +- Научиться фильтровать и ограничивать выборку данных: + - Применять предложение WHERE для фильтрации строк по различным условиям + - Использовать операторы сравнения и логические операторы + - Работать с диапазонами значений и списками + - Выполнять выборку уникальных значений с помощью DISTINCT + +- Освоить работу с числовыми функциями: + - Применять функции округления + - Выполнять арифметические операции над числовыми данными + - Создавать вычисляемые поля в результатах запросов + +- Изучить символьные функции: + - Использовать функции конкатенации строк + - Применять функции изменения регистра + - Работать с функциями определения длины строк + - Использовать функции поиска позиции символов + +- Освоить функции работы с датами: + - Выполнять операции с датами и временем + - Вычислять разницу между датами + - Извлекать компоненты дат + - Применять функции преобразования типов данных + +- Научиться использовать условные выражения: + - Применять функцию COALESCE для обработки NULL-значений + - Использовать конструкцию CASE для создания условной логики в запросах + - Формировать сложные вычисляемые поля с использованием условий + +- Развить навыки анализа и отладки SQL-запросов: + - Находить и исправлять синтаксические ошибки в запросах + - Оптимизировать структуру запросов для получения требуемых результатов + + === Исходные данные +Для выполнения практической работы используется учебная база данных `EmployeesDepartments`, содержащая информацию о сотрудниках компании и структуре отделов. + + +1. Таблица `EMPLOYEES` + +Содержит информацию о сотрудниках компании со следующими полями: +- `EMPLOYEE_ID` – идентификационный номер сотрудника (числовой) +- `FIRST_NAME` – имя сотрудника (строковый) +- `LAST_NAME` – фамилия сотрудника (строковый) +- `EMAIL` – электронная почта (строковый) +- `PHONE_NUMBER` – номер телефона (строковый) +- `HIRE_DATE` – дата найма (дата) +- `JOB_ID` – идентификатор должности (строковый) +- `SALARY` – оклад сотрудника (числовой) +- `COMMISSION_PCT` – процент комиссионных (числовой) +- `MANAGER_ID` – идентификатор менеджера (числовой) +- `DEPARTMENT_ID` – идентификатор отдела (числовой) + +2. Таблица DEPARTMENTS + +Содержит информацию об отделах компании со следующими полями: +- `DEPARTMENT_ID` – идентификационный номер отдела (числовой) +- `DEPARTMENT_NAME` – название отдела (строковый) +- `MANAGER_ID` – идентификатор руководителя отдела (числовой) +- `LOCATION_ID` – идентификатор местоположения (числовой) + +3. Таблица JOB_GRADES + +Содержит информацию о разрядах различных должностей. + === Выполнение работы ==== Задание 1. Описание структуры таблицы, выборка данных из таблицы, задание имен столбцов, сортировка строк с помощью предложения ORDER BY @@ -693,12 +775,25 @@ ORDER BY "LAST_NAME" ASC; ] ```sql - +SELECT "EMPLOYEE_ID", + "LAST_NAME", + "SALARY", + ROUND("SALARY" * 1.095) AS "New Salary" +FROM "EmployeesDepartments"."EMPLOYEES" +ORDER BY "EMPLOYEE_ID"; ``` +- выбираются столбцы `EMPLOYEE_ID`, `LAST_NAME` и `SALARY` из таблицы `EMPLOYEES`; +- новый столбец `New Salary` рассчитывается как оклад, увеличенный на 9.5%: `SALARY` $dot$ 1.095; +- функция `ROUND` округляет полученное значение до целого числа; +- с помощью `ORDER BY "EMPLOYEE_ID"` строки сортируются по номеру сотрудника. + +Результат выполнения запроса представлен на рисунке 20. + + #align(center)[ #figure( - image("assets/"), + image("assets/20.png"), supplement: [Рис.], caption: [Результат выполнения запроса.] ) @@ -715,12 +810,26 @@ ORDER BY "LAST_NAME" ASC; ] ```sql - +SELECT "EMPLOYEE_ID", + "LAST_NAME", + "SALARY", + ROUND("SALARY" * 1.095) AS "New Salary", + ROUND("SALARY" * 1.095) - "SALARY" AS "Increase" +FROM "EmployeesDepartments"."EMPLOYEES" +ORDER BY "EMPLOYEE_ID"; ``` +- используется выражение из задания 3.1 для расчёта нового оклада, округлённого функцией `ROUND`; +- добавлен новый столбец `Increase`, который вычисляется как разница между новым и старым окладом; +- это позволяет увидеть, насколько увеличилась зарплата каждого сотрудника после повышения на 9.5%; +- строки сортируются по идентификатору сотрудника. + + +Результат выполнения запроса представлен на рисунке 21. + #align(center)[ #figure( - image("assets/"), + image("assets/21.png"), supplement: [Рис.], caption: [Результат выполнения запроса.] ) @@ -730,27 +839,376 @@ ORDER BY "LAST_NAME" ASC; ===== 4.1 Создайте запрос для вывода всех данных из таблицы EMPLOYEES. Разделите столбцы запятыми. Назовите столбец THE_OUTPUT. Результат запроса должен быть схож с таблицей 19. +#align(center)[ + #figure( + table(columns: 1)[*THE_OUTPUT*][100, Steven, King, SKING, 515.123.4567, 2002-06-17, AD_PRES, 24000.00, , , 90][101, Neena, Kochhar, NKOCHHAR, 515.123.4568, 2004-09-21, AD_VP, 17000.00, , 100, 90][102, Lex, De Haan, LDEHAAN, 515.123.4569, 2008-01-13, AD_VP, 17000.00, , 100, 90][103, Alexander, Hunold, AHUNOLD, 590.423.4567, 2005-01-03, IT_PROG, 9000.00, , 102, 60][104, Bruce, Ernst, BERNST, 590.423.4568, 2006-05-21, IT_PROG, 6000.00, , 103, 60][107, Diana, Lorentz, DLORENTZ, 590.423.5567, 2014-02-07, IT_PROG, 4200.00, , 103, 60][$dots$], + supplement: [Табл.], + caption: [Результат выполнения запроса.] + ) +] +```sql +SELECT + CONCAT( + "EMPLOYEE_ID", ', ', + "FIRST_NAME", ', ', + "LAST_NAME", ', ', + "EMAIL", ', ', + "PHONE_NUMBER", ', ', + "HIRE_DATE", ', ', + "JOB_ID", ', ', + "SALARY", ', ', + "COMMISSION_PCT", ', ', + "MANAGER_ID", ', ', + "DEPARTMENT_ID" + ) AS "THE_OUTPUT" +FROM "EmployeesDepartments"."EMPLOYEES"; +``` + +- каждое значение соединяется через запятую и пробел ', '; +- функция `CONCAT` объединяет текстовые фрагменты; +- все данные из таблицы выводятся в один столбец `THE_OUTPUT`. + +Результат выполнения запроса представлен на рисунке 22. + +#align(center)[ + #figure( + image("assets/22.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] ===== 4.2 Создайте запрос для вывода фамилий служащих (первая буква каждой фамилии должна быть заглавной, а остальные - строчными) и длину каждой фамилии для тех служащих, фамилия которых начинается с символа _J, A_ или _M_. Присвойте соответствующие заголовки столбцам. Результат выполнения запроса должен соответствовать таблице 20. + +#align(center)[ + #figure( + table(columns: 2)[*Name*][*Length*]["Abel"][4]["Almeida Castro"][14]["Alves Rocha"][11]["Matos"][5]["Mourgos"][7], + supplement: [Табл.], + caption: [Результат выполнения запроса.] + ) +] + +```sql +SELECT + INITCAP("LAST_NAME") AS "Name", + LENGTH("LAST_NAME") AS "Length" +FROM "EmployeesDepartments"."EMPLOYEES" +WHERE UPPER(SUBSTR("LAST_NAME", 1, 1)) IN ('J', 'A', 'M'); +``` + +- `INITCAP("LAST_NAME")` делает первую букву фамилии заглавной, а остальные строчными; +- `LENGTH("LAST_NAME")` вычисляет количество символов в фамилии; +- `SUBSTR("LAST_NAME", 1, 1)` извлекает первый символ фамилии; +- `UPPER(...) IN ('J','A','M')` отбирает только тех сотрудников, чья фамилия начинается на _J_, _A_ или _M_ (без учёта регистра); +- Результат выводится в два столбца: + - `Name` — фамилия с правильным регистром, + - `Length` — длина фамилии. + +Результат выполнения запроса представлен на рисунке 23. + +#align(center)[ + #figure( + image("assets/23.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] + + + ===== 4.3 Создайте запрос для вывода информации по каждому служащему в следующем виде: \<фамилия\> зарабатывает \<оклад\> в месяц, но желает \<утроенный оклад\>. Назовите столбец Dream Salaries. Результат запроса должен быть схож с таблицей 21. +#align(center)[ + #figure( + table(columns: 1)[*Dream Salaries*][King зарабатывает 24000 в месяц, но желает 72000][Kochhar зарабатывает 17000 в месяц, но желает 51000][De Haan зарабатывает 17000 в месяц, но желает 51000][Whalen зарабатывает 4400 в месяц, но желает 13200][Higgins зарабатывает 12000 в месяц, но желает 36000][$dots$], + supplement: [Табл.], + caption: [Результат выполнения запроса.] + ) +] + +```sql +SELECT + CONCAT( + "LAST_NAME", + ' зарабатывает ', + "SALARY", + ' в месяц, но желает ', + "SALARY" * 3 + ) AS "Dream Salaries" +FROM "EmployeesDepartments"."EMPLOYEES"; +``` + +- `CONCAT` объединяет несколько частей строки в одно выражение; +- `LAST_NAME` фамилия сотрудника; +- `SALARY` его текущий оклад; +- `"SALARY" * 3` утроенный оклад; +- все фрагменты объединяются в предложение. + +Результат выполнения скрипта представлен на рисунке 24. + +#align(center)[ + #figure( + image("assets/24.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] + ==== Задание 5. Составление запросов, требующих функций для работы с датами и функции преобразования типов. ===== 5.1 Напишите запрос для вывода текущей даты. Назовите столбец Date. Результат выполнения запроса должен быть подобен результату, представленному на таблице 22. +#align(center)[ + #figure( + table(columns: 1)[*DATE*][2024-10-20], + supplement: [Табл.], + caption: [Результат выполнения запроса текущей даты.] + ) +] + +```sql +SELECT CURRENT_DATE AS "Date"; +``` + +- `CURRENT_DATE` стандартная функция, возвращающая текущую системную дату; +- `AS "Date"` задаёт имя столбца. + +Резултат выполнения запроса представлен на рисунке 25. + +#align(center)[ + #figure( + image("assets/25.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] + ===== 5.2 Создайте запрос для вывода фамилии и даты найма всех служащих, нанятых в 2011 г. Результат выполнения запроса должен соответствовать таблице 23. +#align(center)[ + #figure( + table(columns: 2)[*LAST_NAME*][*HIRE_DATE*][Alves Rocha][2011-02-06][Hartstein][2011-02-17][Abel][2011-05-11][Hernandez][2011-06-13], + supplement: [Табл.], + caption: [Результат выполнения запроса для служащих, нанятых в 2011г.] + ) +] + +```sql +SELECT "LAST_NAME", "HIRE_DATE" +FROM "EmployeesDepartments"."EMPLOYEES" +WHERE EXTRACT(YEAR FROM "HIRE_DATE") = 2011; +``` + +- `EXTRACT(YEAR FROM "HIRE_DATE")` извлекает год из даты найма; +- `= 2011` выбирает только тех сотрудников, у которых год найма равен 2011. + +Результат выполнения запроса представлен на рисунке 26. + +#align(center)[ + #figure( + image("assets/26.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] + ===== 5.3 Создайте запрос, который позволяет для каждого служащего вывести фамилию, дату найма и вычислят количество месяцев со дня найма до настоящего времени. Назовите столбец MONTH_WORKED. Результаты отсортируйте по количеству отработанных месяцев. Результат выполнения запроса должен быть схож с таблицей 24. +#align(center)[ + #figure( + table(columns: 3)[*LAST_NAME*][*HIRE_DATE*][*MONTH_WORKED*][Safwah][1997-01-06][345][King][2002-06-17][280][Whalen][2002-09-17][277][Kochhar][2004-09-21][252][Steiner][2004-11-02][251][Hunold][2005-01-03][249][Ernst][2006-05-21][232][Reinhard][2007-07-25][218][$dots$][$dots$][$dots$], + supplement: [Табл.], + caption: [Результат выполнения запроса.] + ) +] + +```sql +SELECT + "LAST_NAME", + "HIRE_DATE", + (EXTRACT(YEAR FROM AGE(CURRENT_DATE, "HIRE_DATE")) * 12 + + EXTRACT(MONTH FROM AGE(CURRENT_DATE, "HIRE_DATE"))) AS "MONTH_WORKED" +FROM "EmployeesDepartments"."EMPLOYEES" +ORDER BY "MONTH_WORKED" DESC; +``` + +- `AGE(CURRENT_DATE, "HIRE_DATE")` — возвращает интервал между двумя датами; +- `EXTRACT(YEAR FROM AGE(...)) * 12 + EXTRACT(MONTH FROM AGE(...))` переводит годы и месяцы в общее количество месяцев; +- `ORDER BY "MONTH_WORKED" DESC` сортирует по количеству месяцев в порядке убывания. + +Результат выполнения запроса представлен на рисунке 27. + +#align(center)[ + #figure( + image("assets/27.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] + ===== 5.4 Создайте запрос, который позволяет для каждого служащего вывести фамилию, дату найма и день недели, когда он был нанят на работу. Назовите последний столбец DAY. Отсортируйте результаты по датам. Результат выполнения запроса должен быть схож с таблицей 25. +#align(center)[ + #figure( + table(columns: 3)[*LAST_NAME*][*HIRE_DATE*][*DAY*][Stocks][2015-12-16][WEDNESDAY][Newton][2015-12-16][WEDNESDAY][Heiden][2015-07-06][MONDAY][Ricci][2015-05-17][SUNDAY][Zlotkey][2015-01-29][THURSDAY][Mourgos][2014-11-16][SUNDAY][Grant][2014-05-24][SATURDAY][Bell][2014-04-01][TUESDAY][Lorentz][2014-02-07][FRIDAY][$dots$][$dots$][$dots$], + supplement: [Табл.], + caption: [Результат выполнения запроса.] + ) +] + +```sql +SELECT + "LAST_NAME", + "HIRE_DATE", + TO_CHAR("HIRE_DATE", 'FMDay') AS "DAY" +FROM "EmployeesDepartments"."EMPLOYEES" +ORDER BY "HIRE_DATE"; +``` + +- `TO_CHAR("HIRE_DATE", 'FMDay')` преобразует дату в название дня недели; + - `FM` убирает лишние пробелы в начале и конце; + - возвращается день недели полностью; +- столбец переименован в `DAY`; +- `ORDER BY "HIRE_DATE"` сортирует результаты по дате найма, от ранних к поздним. + +Результат выполнения запроса представлен на рисунке 28. + +#align(center)[ + #figure( + image("assets/28.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] + ==== Задание 6. Составление запросов, требующих применения условных выражений. ===== 6.1 Создайте запрос, который позволяет для каждого служащего вывести фамилию и сумму комиссионных. Если служащий не зарабатывает комиссионных, укажите в столбце "No Commission". Назовите столбец COMM. Используются ф-ции преобразования типов и условное выражение COALESCE. Результат выполнения запроса должен быть схож с таблицей 25. -===== 6.2 Создайте запрос, который позволяет для каждого служащего вывести должность и её разряда (grade), используя условное выражение CASE. Разряд каждого типа должности JOB_ID приведён на рисунке 6.2, а результат выполнения запроса должен быть схож с таблицей 26. +#align(center)[ + #figure( + table(columns: 2)[*LAST_NAME*][*COMM*][King][No Commission][Kochhar][No Commission][De Haan][No Commission][Hunold][No Commission][Ernst][No Commission][Lorentz][No Commission][Mourgos][No Commission][Rajs][No Commission][Davies][No Commission][Matos][No Commission][Vargas][No Commission][Zlotkey][0.20][Abel][0.30][$dots$][$dots$], + supplement: [Табл.], + caption: [Результат выполнения запроса.] + ) +] + +```sql +SELECT + "LAST_NAME", + COALESCE(TO_CHAR("COMMISSION_PCT", 'FM0.00'), 'No Commission') AS "COMM" +FROM "EmployeesDepartments"."EMPLOYEES"; +``` + +- `TO_CHAR("COMMISSION_PCT", 'FM0.00')` преобразует числовое значение комиссионных в текстовый формат с двумя десятичными знаками; +- `COALESCE(..., 'No Commission')` если значение комиссионных равно NULL, выводится строка 'No Commission'; +- столбец переименован в `COMM`; +- вывод показывает фамилию сотрудника и либо его комиссионные, либо надпись 'No Commission'. + +Результат выполнения запроса представлен на рисунке 29. + +#align(center)[ + #figure( + image("assets/29.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] + +===== 6.2 Создайте запрос, который позволяет для каждого служащего вывести должность и её разряда (grade), используя условное выражение CASE. Разряд каждого типа должности JOB_ID приведён в таблице 26, а результат выполнения запроса должен быть схож с таблицей 27. + +#align(center)[ + #figure( + table(columns: 2)[*Должность*][*Разряд*][AD_PRES][E][ST_MAN][D][IT_PROG][C][SA_REP][B][ST_CLERK][A][Другая][0], + supplement: [Табл.], + caption: [Соответствие каждого типа должности и разряда.] + ) +] + +#align(center)[ + #figure( + table(columns: 3)[*LAST_NAME*][*JOB_ID*][*GRADE*][King][AD_PRES][E][Kochhar][AD_VP][0][De Haan][AD_VP][0][Whalen][AD_ASST][0][Higgins][AC_MGR][0][Gietz][AC_ACCOUNT][0][Zlotkey][SA_MAN][0][Abel][SA_REP][B][Taylor][SA_REP][B][Grant][SA_REP][B][Mourgos][ST_MAN][D][Rajs][ST_CLERK][A][King][AD_PRES][E][Kochhar][AD_VP][0][De Haan][AD_VP][0][Whalen][AD_ASST][0][$dots$][$dots$][$dots$], + supplement: [Табл.], + caption: [Результат выполнения запроса.] + ) +] + + +```sql +SELECT + "JOB_ID" AS "Должность", + CASE "JOB_ID" + WHEN 'AD_PRES' THEN 'E' + WHEN 'ST_MAN' THEN 'D' + WHEN 'IT_PROG' THEN 'C' + WHEN 'SA_REP' THEN 'B' + WHEN 'ST_CLERK' THEN 'A' + ELSE '0' + END AS "GRADE" +FROM "EmployeesDepartments"."EMPLOYEES"; +``` + +- `CASE ... WHEN ... THEN ... ELSE ... END` позволяет для каждого типа должности присвоить соответствующий разряд; +- должности, не указанные в таблице 26, получают разряд '0' через `ELSE '0'`; +- cтолбцы переименованы в `Должность` и `GRADE`; + +Результат выполнения запроса представлен на рисунке 30. + +#align(center)[ + #figure( + image("assets/30.png"), + supplement: [Рис.], + caption: [Результат выполнения запроса.] + ) +] === Выводы и анализ результатов работы +В ходе выполнения работы были успешно освоены основные конструкции языка SQL для работы с реляционными базами данных. Все поставленные задачи выполнены, запросы составлены корректно и возвращают ожидаемые результаты. + + - Научился формировать запросы на выборку данных с использованием оператора `SELECT` + - Освоил использование предложений `WHERE` для фильтрации данных по различным условиям + - Изучил применение `ORDER BY` для сортировки результатов запросов + - Научился использовать `DISTINCT` для выборки уникальных значений + - Освоил создание псевдонимов для столбцов с помощью `AS` + - Применил операторы сравнения + - Использовал логические операторы + - Освоил работу с операторами `BETWEEN`, `IN`, `NOT IN` для проверки диапазонов и списков значений + - Научился работать с `NULL` значениями через `IS NULL` и `IS NOT NULL` + - Применил оператор `LIKE` для поиска по шаблону в текстовых данных + - Освоил функции округления `ROUND()` для математических вычислений + - Научился выполнять арифметические операции в запросах (сложение, вычитание, умножение, деление) + - Создавал вычисляемые поля для расчёта новых значений на основе существующих данных + - Применил функцию `CONCAT()` для объединения нескольких строковых значений + - Использовал `INITCAP()` для форматирования текста с заглавной первой буквой + - Освоил `LENGTH()` для определения длины строк + - Применил `SUBSTR()` для извлечения подстрок + - Научился использовать оператор конкатенации `||` в PostgreSQL + - Освоил функцию `CURRENT_DATE` для получения текущей системной даты + - Применил `EXTRACT()` для извлечения компонентов даты + - Использовал функцию `AGE()` для вычисления разницы между датами + - Научился форматировать даты с помощью `TO_CHAR()` для вывода дней недели + - Выполнил сложные вычисления с датами, такие как расчёт количества отработанных месяцев + - Освоил функцию `COALESCE()` для обработки `NULL` значений и замены их на заданные значения + - Применил конструкцию `CASE ... WHEN ... THEN ... ELSE ... END` для создания условной логики непосредственно в запросах + - Научился создавать сложные вычисляемые поля с использованием множественных условий + - Развил навыки поиска и исправления синтаксических ошибок в SQL-запросах + - Научился анализировать структуру таблиц через `information_schema.columns` + - Понял важность правильного использования кавычек для регистрозависимых имён в PostgreSQL + - Освоил методику пошаговой разработки сложных запросов + + +В процессе выполнения работы возникли следующие сложности: + +- В PostgreSQL при создании объектов с кавычками имена становятся регистрозависимыми. Решение: последовательное использование двойных кавычек для всех идентификаторов таблиц и столбцов. + +- Особенности сравнения и обработки NULL потребовали использования специальных конструкций. Решение: изучение документации и применение соответствующих функций. + +- Получение названий дней недели на английском языке потребовало использования функции `TO_CHAR()` с правильным форматом. Решение: применение модификатора `FM` для удаления лишних пробелов. + +- Расчёт количества месяцев между датами потребовал комбинирования функций `AGE()` и `EXTRACT()`. Решение: декомпозиция задачи на вычисление отдельно лет и месяцев с последующим их объединением. + +В результате выполнения практической работы была достигнута поставленная цель: освоены основные конструкции SQL и получены практические навыки составления запросов различной сложности для работы с реляционными базами данных. +