diff --git a/lab_11.sql b/lab_11.sql new file mode 100644 index 0000000..e19f443 --- /dev/null +++ b/lab_11.sql @@ -0,0 +1,249 @@ +--Лабораторная 11. + +-- Задание 1. Основы языка pl/pgSQL + +-- 1. Напишите анонимный блок для вывода элементов из двумерного массива. +-- Для этого объявите переменную и передайте ей двумерный массив +-- ARRAY[ARRAY[ 10, 20, 30], ARRAY[100,200,300]] +-- В исполняемой секции блока (BEGIN … END) с помощью цикла +-- организуйте поэлементный вывод + +do $$ +declare + a integer[][]; + i integer; + j integer; + +begin + a := array[ + array[10, 20, 30], + array[100, 200, 300] + ]; + + for i in array_lower(a, 1)..array_upper(a, 1) loop + for j in array_lower(a, 2)..array_upper(a, 2) loop + raise notice 'a[%,%] = %', i, j, a[i][j]; + end loop; + end loop; +end; +$$ language plpgsql; + +-- 2. C помощью средств pl\pgsql, напишите анонимный блок, +-- выводящий следующие сообщения: +do $$ +declare + i int; + j int; + line text; +begin + for i in 1..5 loop + line := ''; + for j in 1..i loop + line := line || j || ' '; + end loop; + raise notice 'NOTICE: %', trim(line); + end loop; + + for i in 1..5 loop + line := ''; + for j in 1..(6 - i) loop + line := line || j || ' '; + end loop; + raise notice 'NOTICE: %', trim(line); + end loop; +end; +$$ language plpgsql; + +-- 3. Напишите анонимный блок, который подсчитывает сколько требуется +-- работать в компании, чтобы получать 6-ти значную зарплату. Стартовая +-- зарплата 500$ каждый год рост 10%. Вывести сообщение: +-- «Имея стартовую зарплату [зарплата], надо работать [кол-во лет] лет, +-- чтобы достичь 6-тизначных цифр: [конечная зарплата].». + +do $$ +declare + start_salary numeric := 500; + current_salary numeric := start_salary; + years int := 0; +begin + while current_salary < 100000 loop + current_salary := current_salary * 1.1; + years := years + 1; + end loop; + + raise notice + 'имея стартовую зарплату %, надо работать % лет, чтобы достичь 6-тизначных цифр: %.', + start_salary, years, current_salary::numeric(10,3); +end; +$$ language plpgsql; + +-- Задание 2. Создание функций и процедур на языке SQL + +-- 1. Создайте скалярную функцию. Функция должна принимать произвольную дату +-- и возвращать количество дней между полученной датой и текущей датой. +-- Протестируйте созданную функцию. Приведите код +create function schema2.days_between_today(p_date date) +returns integer +language sql +as +$$ + select (current_date - p_date)::int; +$$; + +select schema2.days_between_today(date '2025-09-11'); + +select schema2.days_between_today(current_date); + +-- 2. Создайте функцию. Функция должна принимать название города, а возвращать +-- список подразделений, расположенных в указанном городе, и количество сотрудников +-- в этих подразделениях. +-- Протестируйте созданную функцию. Приведите код + + +create or replace function schema2.get_departments_by_city(p_city text) +returns table ( + department_name text, + employees_count int +) +language sql +as +$$ + select + d.department_id, + count(e.employee_id) as employees_count + from schema1.departments d + join schema1.locations a + on d.location_id = a.location_id + left join schema1.employees e + on e.department_id = d.department_id + where a.city = p_city + group by d.department_id + order by d.department_id; +$$; + + +insert into schema1.locations (location_id, street_address, postal_code, city, country_id) +values + (14, 'вшэ', '0001', 'paris', + (select country_id from schema1.countries where country_name = 'France')), + (15, 'сбпгу', '0102', 'gamburg', + (select country_id from schema1.countries where country_name = 'Germany')), + (13, 'чето1', '1142', 'tokyo', + (select country_id from schema1.countries where country_name = 'Japan')); + +insert into schema1.departments (department_id,department_name,manager_id, location_id) values +(10,'DEP1',14,14),(2,'DEP2',5,15); + +insert into schema1.employees +(employee_id, first_name, last_name, email, hire_date, job_id, department_id) +values +(100, 'John', 'Doe', 'john@paris.com', current_date, 'DEV1', 10); + + +select * +from schema2.get_departments_by_city('paris'); +-- работает (я там что-то когда-то удалял видимо, пришлось добавить) + +-- 3. Создайте функцию. Функция должна принимать идентификатор должности, а +-- возвращать название должности и количество сотрудников, занимающих эту должность. +-- Протестируйте созданную функцию. Приведите код + +create function schema2.get_employees_by_job(p_job_id varchar) +returns table ( + job_title text, + employees_count int +) +language sql +as +$$ + select + j.job_title, + count(e.employee_id) as employees_count + from schema1.jobs j + left join schema1.employees e + on e.job_id = j.job_id + where j.job_id = p_job_id + group by j.job_id; +$$; + +select * +from schema2.get_employees_by_job('DEV1'); + +-- 4. Создайте процедуру для добавления новой должности в БД. +create procedure schema2.add_job( + p_job_id varchar, + p_job_title text, + p_min_salary numeric, + p_max_salary numeric +) +language sql +as +$$ + insert into schema1.jobs (job_id, job_title, min_salary, max_salary) + values (p_job_id, p_job_title, p_min_salary, p_max_salary); +$$; + +call schema2.add_job('dev', 'middle developer', 500, 1500); + +select * +from schema1.jobs +where job_id = 'dev'; + +-- 5. Создайте в вашей БД 2 таблицы: таблицу пользователей users и таблицу +-- друзей пользователей friend +create table public.users ( + user_id serial4 not null primary key, + user_name text, + user_added timestamptz +); + +create table public.friends ( + user_id int4 not null, + friend_user_id int4 not null, + primary key (user_id, friend_user_id), + foreign key (user_id) references public.users(user_id), + foreign key (friend_user_id) references public.users(user_id) +); + +-- a. Заполните таблицы данными +insert into public.users (user_name, user_added) +values + ('даня', now()), + ('ваня', now()), + ('борис', now()), + ('саша', now()), + ('катя', now()), + ('миша', now()); + +insert into public.friends (user_id, friend_user_id) +values + (1, 2), + (1, 4), + (2, 3), + (4, 6), + (5, 1), + (6, 2); + +select * from public.friends; + +-- b. Создайте функцию, которая будет принимать номер пользователя, а +-- выводить идентификатор пользователя и массив всех его друзей +create function public.get_user_friends(p_user_id int) +returns table ( + user_id int, + friends int[] +) +language plpgsql +as +$$ +begin + return query + select + p_user_id as user_id, + array_agg(f.friend_user_id order by f.friend_user_id) as friends + from public.friends f + where f.user_id = p_user_id; +end; +$$; + +select * from public.get_user_friends(4);