Files
DB.mephi_ada/3 sem/Lab/Lab#6/lab6_done.sql
T
2024-02-15 15:29:30 +03:00

451 lines
12 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Вариант 1 || Работа 6 || Антипенко, Дробышевский */
-- Task 1 --
/* a) Напишите запрос, используя конструкцию WITH, выбирающий
рекурсивно сотрудника с идентификатором 1 и все его подчинённых,
как прямых, так и подчинённых более низкого ранга*.
b) Напишите программу на языке PL/SQL, печатающую на экран фамилию
и имя сотрудника с идентификатором 1 и всех его подчинённых, как
прямых, так и подчинённых более низкого ранга. */
-- Пункт а)
WITH RECURSIVE tmp AS (
SELECT id, first_name, last_name, manager_id, 1 AS level
FROM bd6_employees
WHERE id = 1
UNION all
SELECT e.id, e.first_name, e.last_name, e.manager_id, t.level + 1
FROM bd6_employees e
JOIN tmp t ON e.manager_id = t.id
)
SELECT *
FROM tmp
;
-- Пункт б)
CREATE OR REPLACE PROCEDURE depa(integer) AS $$
DECLARE
d_attrs RECORD;
i integer;
l integer;
BEGIN
FOR d_attrs IN
(
SELECT id,last_name, first_name, manager_id
FROM bd6_employees
ORDER BY manager_id
)
LOOP
IF d_attrs.manager_id=$1 THEN
RAISE INFO ' % % % % ', d_attrs.first_name, d_attrs.last_name, d_attrs.id, d_attrs.manager_id;
l:= d_attrs.id;
CALL depa(l);
END IF;
END LOOP;
END $$ LANGUAGE plpgsql;
CREATE OR REPLACE PROCEDURE dep(integer) AS $$
DECLARE
d_attrs RECORD;
BEGIN
FOR d_attrs IN
(
SELECT
id,
last_name,
first_name,
manager_id
FROM bd6_employees
ORDER BY manager_id
)
LOOP
IF d_attrs.id=$1 THEN
RAISE INFO ' % % % % ', d_attrs.first_name, d_attrs.last_name, d_attrs.id, d_attrs.manager_id;
END IF;
END LOOP;
CALL depa($1);
END $$ LANGUAGE plpgsql;
CALL dep(1);
-- Task 2 --
/* Напишите программу на языке PL/SQL, выбирающую строки из таблицы
employees в порядке возрастания заработной платы (salary) и печатающие на
экран следующие данные: фамилия, имя, модифицированная заработная
плата. Модифицированная заработная плата получается следующим
образом: у первого по порядку сотрудника она округляется до сотен в
меньшую сторону, а у всех последующих сотрудников она сначала
увеличивается на остаток от округления, полученный от предыдущего
сотрудника, а затем округляется до сотен в меньшую сторону. */
UPDATE bd6_employees SET salary_in_euro = 299 WHERE id = 3;
CREATE OR REPLACE PROCEDURE print_employees() AS $$
DECLARE
current_salary INTEGER;
m_salary INTEGER;
mod_salary INTEGER := 0;
employee_rec RECORD;
BEGIN
FOR employee_rec IN
(
SELECT last_name, first_name, salary_in_euro
FROM bd6_employees
ORDER BY salary_in_euro
)
LOOP
current_salary := employee_rec.salary_in_euro;
m_salary := ((current_salary + mod_salary) / 100) * 100;
RAISE NOTICE 'Employee: % % || Modified Salary: %', employee_rec.last_name, employee_rec.first_name, m_salary;
mod_salary := mod(current_salary + mod_salary,100);
END LOOP;
END $$ LANGUAGE plpgsql;
CALL print_employees();
SELECT *
FROM bd6_employees
ORDER BY salary_in_euro;
-- Task 3 --
/* Напишите программу на языке PL/SQL, удаляющую 10 сотрудников с
самой маленькой заработной платой. При этом их заработная плата должна
добавиться 10 сотрудникам с самой большой заработной платой. Причём
самая маленькая заработная плата должна добавиться к человеку с самой
большой заработной платой. 2-я с конца заработная плата должна добавиться
к человеку со второй по размеру заработной платой и т.д. */
CREATE OR REPLACE FUNCTION rearrange_salaries() RETURNS VOID AS $$
DECLARE
salaries RECORD;
small NUMERIC[];
larg NUMERIC[];
const CONSTANT INTEGER = 3;
BEGIN
FOR salaries IN
SELECT id, salary_in_euro
FROM bd6_employees
ORDER BY salary_in_euro
LIMIT const
LOOP
small = array_append(small, (SELECT salary_in_euro FROM bd6_employees WHERE id = salaries.id));
DELETE FROM bd6_employees
WHERE id = salaries.id;
END LOOP;
FOR salaries IN
SELECT id, salary_in_euro
FROM bd6_employees
ORDER BY salary_in_euro DESC
LIMIT const
LOOP
larg = array_append(larg, (SELECT id FROM bd6_employees WHERE id = salaries.id));
END LOOP;
FOR i IN 1..const
LOOP
UPDATE bd6_employees
SET salary_in_euro = salary_in_euro + small[i]
WHERE id = larg[i];
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT rearrange_salaries();
-- Task 4 --
/* Создайте таблицу spiral с 5 полями f1, f2, f3, f4, f5 целые числа.
Напишите программу на языке PL/SQL, заполняющую данную таблицу 1000
строк по следующему принципу:
1 2 3 4 5
10 9 8 7 6
11 12 13 14 15
20 19 18 17 16
21 22 23 24 25 */
CREATE OR REPLACE PROCEDURE f() AS $$
DECLARE d_attrs RECORD;
BEGIN
FOR d_attrs IN WITH RECURSIVE tmp AS (
SELECT 1+i*5 AS f1, 2+i*5 AS f2, 3+i*5 AS f3, 4+i*5 AS f4,5+i*5 AS f5
FROM generate_series(0,199) i)
SELECT * FROM tmp
LOOP
case
when ( mod(d_attrs.f1,2)!=0)
then RAISE INFO ' % % % % %', d_attrs.f1, d_attrs.f2, d_attrs.f3, d_attrs.f4, d_attrs.f5;
when ( mod(d_attrs.f1,2)=0)
then RAISE INFO ' % % % % %', d_attrs.f5, d_attrs.f4, d_attrs.f3, d_attrs.f2, d_attrs.f1;
end case;
END LOOP;
END $$ LANGUAGE plpgsql;
call f();
-- Task 7 from lab4 --
CREATE table staff(
id integer primary key,
name varchar(64) NOT NULL,
department varchar(64) NOT NULL
);
CREATE SEQUENCE staff_id_seq
START WITH 12
CYCLE
INCREMENT BY 8
CACHE 100;
INSERT INTO staff VALUES
(nextval('staff_id_seq'), 'Ivan Makarenko', 'Director');
INSERT INTO staff
(SELECT nextval('staff_id_seq'), last_name, department_name
FROM employees e JOIN departments d ON e.department_id = d.department_id);
UPDATE staff SET department = 'Innovations department'
WHERE id < 40;
DELETE FROM staff
WHERE name ILIKE('%K%');
CREATE VIEW dep_staff_counts AS
SELECT department, COUNT(*) AS ecount
FROM staff
GROUP BY department;
SELECT * FROM dep_staff_counts;
-- CREATE OR REPLACE PROCEDURE department_names(integer) AS $$
-- DECLARE
-- d_attrs RECORD;
-- i INTEGER;
-- l INTEGER;
-- BEGIN
-- FOR d_attrs IN
-- (
-- SELECT id,last_name, first_name, manager_id
-- FROM bd6_employees order by manager_id
-- )
-- LOOP
-- IF d_attrs.manager_id=$1 THEN
-- RAISE INFO ' % % % % ', d_attrs.first_name, d_attrs.last_name, d_attrs.id, d_attrs.manager_id;
-- l:= d_attrs.id;
-- CALL department_names(l);
-- END IF;
-- END LOOP;
-- END $$ LANGUAGE plpgsql;
-- CREATE OR REPLACE PROCEDURE department_names2(integer) AS $$
-- DECLARE d_attrs RECORD;
-- BEGIN
-- FOR d_attrs IN
-- (
-- SELECT id,last_name, first_name, manager_id
-- FROM bd6_employees
-- order by manager_id
-- )
-- LOOP
-- if d_attrs.id=$1 then
-- RAISE INFO ' % % % % ', d_attrs.first_name, d_attrs.last_name, d_attrs.id, d_attrs.manager_id;
-- end if;
-- END LOOP;
-- CALL department_names($1);
-- END $$ LANGUAGE plpgsql;
-- CALL department_names2(4);
/* Вариант 1 || Работа 6 || Антипенко, Дробышевский */
-- Task 1 --
-- Пункт а)
WITH RECURSIVE tmp AS (
SELECT id, first_name, last_name, manager_id, 1 AS level
FROM bd6_employees
WHERE id = 1
UNION all
SELECT e.id, e.first_name, e.last_name, e.manager_id, t.level + 1
FROM bd6_employees e
JOIN tmp t ON e.manager_id = t.id
)
SELECT *
FROM tmp
;
-- Пункт б)
CREATE OR REPLACE PROCEDURE depa(integer) AS $$
DECLARE
d_attrs RECORD;
i integer;
l integer;
BEGIN
FOR d_attrs IN
(
SELECT id,last_name, first_name, manager_id
FROM bd6_employees
ORDER BY manager_id
)
LOOP
IF d_attrs.manager_id=$1 THEN
RAISE INFO ' % % % % ', d_attrs.first_name, d_attrs.last_name, d_attrs.id, d_attrs.manager_id;
l:= d_attrs.id;
CALL depa(l);
END IF;
END LOOP;
END $$ LANGUAGE plpgsql;
CREATE OR REPLACE PROCEDURE dep(integer) AS $$
DECLARE
d_attrs RECORD;
BEGIN
FOR d_attrs IN
(
SELECT
id,
last_name,
first_name,
manager_id
FROM bd6_employees
ORDER BY manager_id
)
LOOP
IF d_attrs.id=$1 THEN
RAISE INFO ' % % % % ', d_attrs.first_name, d_attrs.last_name, d_attrs.id, d_attrs.manager_id;
END IF;
END LOOP;
CALL depa($1);
END $$ LANGUAGE plpgsql;
CALL dep(1);
-- Task 2 --
UPDATE bd6_employees SET salary_in_euro = 299 WHERE id = 3;
CREATE OR REPLACE PROCEDURE print_employees() AS $$
DECLARE
current_salary INTEGER;
m_salary INTEGER;
mod_salary INTEGER := 0;
employee_rec RECORD;
i INTEGER = 0;
cnt INTEGER;
BEGIN
SELECT COUNT(*) INTO cnt FROM bd6_employees;
FOR employee_rec IN
(
SELECT last_name, first_name, salary_in_euro
FROM bd6_employees
ORDER BY salary_in_euro
)
LOOP
current_salary := employee_rec.salary_in_euro;
IF cnt - 1 = i THEN
m_salary := ((current_salary) / 100) * 100 + mod_salary;
ELSE
m_salary := ((current_salary) / 100) * 100;
END IF;
RAISE NOTICE 'Employee: % % || Modified Salary: %', employee_rec.last_name, employee_rec.first_name, m_salary;
mod_salary := mod_salary + mod(current_salary, 100);
i := i+1;
END LOOP;
END $$ LANGUAGE plpgsql;
CALL print_employees();
SELECT *
FROM bd6_employees
ORDER BY salary_in_euro;
-- Task 3 --
CREATE OR REPLACE FUNCTION rearrange_salaries() RETURNS VOID AS $$
DECLARE
salaries RECORD;
small NUMERIC[];
larg NUMERIC[];
const CONSTANT INTEGER = 10;
BEGIN
FOR salaries IN
SELECT id, salary_in_euro
FROM bd6_employees
ORDER BY salary_in_euro
LIMIT const
LOOP
small = array_append(small, (SELECT salary_in_euro FROM bd6_employees WHERE id = salaries.id));
UPDATE bd6_employees SET manager_id = NULL WHERE manager_id = salaries.id;
DELETE FROM bd6_employees
WHERE id = salaries.id;
END LOOP;
FOR salaries IN
SELECT id, salary_in_euro
FROM bd6_employees
ORDER BY salary_in_euro DESC
LIMIT const
LOOP
larg = array_append(larg, (SELECT id FROM bd6_employees WHERE id = salaries.id));
END LOOP;
FOR i IN 1..const
LOOP
UPDATE bd6_employees
SET salary_in_euro = salary_in_euro + small[i]
WHERE id = larg[i];
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT rearrange_salaries();
-- Task 4 --
CREATE OR REPLACE PROCEDURE f() AS $$
DECLARE d_attrs RECORD;
BEGIN
FOR d_attrs IN WITH RECURSIVE tmp AS (
SELECT 1+i*5 AS f1, 2+i*5 AS f2, 3+i*5 AS f3, 4+i*5 AS f4,5+i*5 AS f5
FROM generate_series(0,199) i)
SELECT * FROM tmp
LOOP
case
when ( mod(d_attrs.f1,2)!=0)
then RAISE INFO ' % % % % %', d_attrs.f1, d_attrs.f2, d_attrs.f3, d_attrs.f4, d_attrs.f5;
when ( mod(d_attrs.f1,2)=0)
then RAISE INFO ' % % % % %', d_attrs.f5, d_attrs.f4, d_attrs.f3, d_attrs.f2, d_attrs.f1;
end case;
END LOOP;
END $$ LANGUAGE plpgsql;
call f();
-- Task 7 from lab4 --
DROP VIEW IF EXISTS dep_staff_counts;
CREATE VIEW dep_staff_counts AS
SELECT department, COUNT(*) AS ecount
FROM staff
GROUP BY department;
SELECT * FROM dep_staff_counts;