From 5d23c3020046c58d134c94d11dad1438c27906e4 Mon Sep 17 00:00:00 2001 From: plidan123 Date: Fri, 19 Dec 2025 22:55:26 +0300 Subject: [PATCH] Add files via upload --- lab_12.sql | 293 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 lab_12.sql diff --git a/lab_12.sql b/lab_12.sql new file mode 100644 index 0000000..1cdec0d --- /dev/null +++ b/lab_12.sql @@ -0,0 +1,293 @@ +--Лабораторная работа 12. Создание процедур и функций на языке plpgsql. Обработка исключений + +-- 1. Создайте функцию, которая будет принимать массив символьных значений и шаблон +-- (например, шаблон телефона). Функция должна возвращать False если хотя бы значение одного +-- элемента массива не соответствует шаблону. Иначе функция должна вернуть – True. +-- Функция должна работать на произвольном количестве элементов массива с произвольным шаблоном. + +create function schema2.check_array( + values_arr text[], + pattern text +) +returns boolean +language plpgsql +as $$ +declare + v text; +begin + if values_arr is null or pattern is null then + return false; + end if; + + foreach v in array values_arr loop + if v !~ pattern then + return false; + end if; + end loop; + + return true; +end; +$$; + +select schema2.check_array( + array['123','456'], '^[0-9]{3}$' +)::text as result; + +-- 2. Создайте процедуру. Процедура должна получать идентификатор +-- сотрудника и его телефон. + +create domain public.phone as text +check ( + value ~ '^8\([0-9]{3}\)[0-9]{3}-[0-9]{4}$' +); +--(не смог найти созданный ранее) + +create or replace procedure schema2.add_employee( + p_employee_id numeric, + p_phone text +) +language plpgsql +as $$ +declare + phones text[]; + digits text; +begin + if p_phone is null or length(trim(p_phone)) = 0 then + raise exception 'поле "телефон" пустое'; + end if; + + select e.phone_number + into phones + from schema1.employees e + where e.employee_id = p_employee_id; + + if not found then + raise exception 'сотрудник с id % не найден', p_employee_id; + end if; + + phones := coalesce(phones, array[]::text[]); + + digits := regexp_replace(p_phone, '\D', '', 'g'); + + if length(digits) = 11 and left(digits, 1) = '8' then + digits := '7' || substr(digits, 2); + end if; + + if digits !~ '^7[0-9]{10}$' then + raise exception 'неверный формат телефона: %', p_phone; + end if; + + if digits = any(phones) then + raise info 'телефон % уже существует у сотрудника %', digits, p_employee_id; + return; + end if; + + update schema1.employees + set phone_number = array_append(phones, digits) + where employee_id = p_employee_id; + + raise info 'номер % добавлен сотруднику % (из "%")', digits, p_employee_id, p_phone; +end; +$$; + + +call schema2.add_employee(13, '+7-999-123-45-67'); + +select employee_id, phone_number +from schema1.employees +where employee_id = 13; +-- номер добавлен успешно + +call schema2.add_employee(13, '8(999)123-4567'); +-- номер существует + +call schema2.add_employee(1000, '8(999)123-4567'); +-- такого сотрудника нет + + + +-- 3. Создайте процедуру для добавления нового департамента. +create procedure schema2.add_department( + department_id numeric, + department_name text, + manager_id numeric, + location_id numeric default null +) +language plpgsql +as $$ +begin + if department_id is null then + raise exception 'не заполнено обязательное поле department_id'; + end if; + + if department_name is null or length(trim(department_name)) = 0 then + raise exception 'не заполнено обязательное поле department_name'; + end if; + + if manager_id is null then + raise exception 'не заполнено обязательное поле manager_id'; + end if; + + begin + insert into schema1.departments(department_id, department_name, manager_id, location_id) + values (department_id, department_name, manager_id, location_id); + + raise info 'департамент "%" (id=%) успешно добавлен', department_name, department_id; + + exception + when unique_violation then + raise exception 'department_id или другое уникальное поле уже существует'; + when foreign_key_violation then + raise exception 'нарушение внешнего ключа (manager_id/location_id)'; + when not_null_violation then + raise exception 'не заполнено обязательное поле (NOT NULL)'; + when check_violation then + raise exception 'значение не прошло проверку (CHECK)'; + when others then + raise exception 'ошибка при добавлении департамента: %', sqlerrm; + end; +end; +$$; + +call schema2.add_department(5001, 'Dept_1', 100); +-- добавлено + +call schema2.add_department(null, 'Dept_2', 100); +-- не заполнено обязательное поле + +call schema2.add_department(9300, 'Dept_3', 9999999, null); +-- ошибка при добавлении департамента + + + +-- 4 +create procedure schema2.add_address( + p_full_address text +) +language plpgsql +as $$ +declare + parts text[]; + v_location_id integer; + v_street text; + v_postal text; + v_city text; + v_country_id integer; +begin + if p_full_address is null or length(trim(p_full_address)) = 0 then + raise exception 'строка адреса пустая'; + end if; + + parts := string_to_array(p_full_address, ';'); + + if array_length(parts, 1) <> 4 then + raise exception 'формат "street_address; postal_code; city; country_id"'; + end if; + + v_street := trim(parts[1]); + v_postal := nullif(trim(parts[2]), ''); + v_city := trim(parts[3]); + + begin + v_country_id := trim(parts[4])::integer; + exception + when invalid_text_representation then + raise exception 'country_id должен быть числом'; + end; + + if v_street is null or v_city is null + or length(v_street)=0 or length(v_city)=0 then + raise exception 'обязательные поля street_address и city'; + end if; + + if exists ( + select 1 + from schema1.locations a + where a.street_address = v_street + and coalesce(a.postal_code,'') = coalesce(v_postal,'') + and a.city = v_city + and a.country_id = v_country_id + ) then + raise exception 'такой адрес уже существует'; + end if; + + select coalesce(max(location_id), 0) + 1 + into v_location_id + from schema1.locations; + + insert into schema1.locations(location_id, street_address, postal_code, city, country_id) + values (v_location_id, v_street, v_postal, v_city, v_country_id); + + raise info 'Адрес добавлен. location_id=%', v_location_id; +end; +$$; + +call schema2.add_address('Pervomayskaya 10; 1010; Saint-P; 1'); +call schema2.add_address('Lomonosova 15; 1010; Москва; 1'); + +select * +from schema1.locations +where postal_code = '1010'; +-- адреса добавлены + + + +-- 5. Создайте функцию. Функция должна принимать название города и +-- возвращать список подразделений, расположенных в указанном городе, +-- и количество сотрудников в этих подразделениях в виде json документ +-- следующего вида: {город: название_города, подразделения: +-- [{название:название_подразделения, сотрудники:[список сотрудников]},{}…]}. +-- Если в указанном городе нет подразделений функция должна возвращать +-- информационное сообщение + +create function schema2.get_departments(p_city text) +returns json +language plpgsql +as $$ +declare + dept_cnt int; + result json; +begin + if p_city is null or length(trim(p_city)) = 0 then + return json_build_object('message', 'Город не задан'); + end if; + + select count(*) + into dept_cnt + from schema1.departments d + join schema1.locations a + on a.location_id = d.location_id + where lower(a.city) = lower(trim(p_city)); + + if dept_cnt = 0 then + return json_build_object('message', format('В городе "%s" нет подразделений', trim(p_city))); + end if; + + select json_build_object( + 'город', trim(p_city), + 'подразделения', + json_agg( + json_build_object( + 'название', d.department_name, + 'сотрудники', + coalesce( + (select json_agg(e.last_name || ' ' || e.first_name order by e.last_name, e.first_name) + from schema1.employees e + where e.department_id = d.department_id), + '[]'::json + ) + ) + order by d.department_name + ) + ) + into result + from schema1.departments d + join schema1.locations a + on a.location_id = d.location_id + where lower(a.city) = lower(trim(p_city)); + + return result; +end; +$$; + +select schema2.get_departments('Paris');