mirror of
https://github.com/ada-dmitry/DB.mephi_ada.git
synced 2026-09-23 23:50:16 +00:00
451 lines
12 KiB
PL/PgSQL
451 lines
12 KiB
PL/PgSQL
/* Вариант 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;
|