Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
332 changes: 332 additions & 0 deletions lab_13.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,332 @@
-- Лабораторная 13. Создание триггеров

-- 1. Реализуйте следующее решение:
-- a. Создайте триггерную функцию check_salary, которая вызывает
-- исключение, если новая зарплата сотрудника больше старой на 100%.
create or replace function schema1.check_salary()
returns trigger
language plpgsql
as $$
begin
if new.salary is distinct from old.salary then
if new.salary > old.salary * 2 then
raise exception
'зарплата увеличена более чем на 100%% (%s, %s, employee_id=%s)',
old.salary, new.salary, old.employee_id;
end if;
end if;

return new;
end;
$$;

-- b. Создайте триггер BEFORE UPDATE - before_update_salary, который
-- вызывает функцию check_salary перед обновлением значения в столбце salary для каждой записи.
create trigger before_update_salary
before update of salary on schema1.employees
for each row
execute function schema1.check_salary();

-- c. Обновите зарплату сотрудника с идентификатором 1 и убедитесь,
-- что триггер сработал и вернул соответствующее сообщение
update schema1.employees
set salary = salary * 3
where employee_id = 1;
-- сработал триггер и изменение не применилось, так как вызвался raise exception

-- d. Переименуйте before_update_salary триггер в salary_before_update
alter trigger before_update_salary
on schema1.employees
rename to salary_before_update;

-- e. Отключите триггер salary_before_update. Обновите зарплату сотрудника
-- с идентификатором 2 и убедитесь, что триггер не сработал.
alter table schema1.employees
disable trigger salary_before_update;

update schema1.employees
set salary = salary * 3
where employee_id = 2;
-- изменилась

-- f. Измените имя функции check_salary на validate_salary.
alter function schema1.check_salary()
rename to validate_salary;

-- g. Измените «привязку» триггера к триггерной функции validate_salary
drop trigger salary_before_update on schema1.employees;

create trigger salary_before_update
before update of salary on schema1.employees
for each row
execute function schema1.validate_salary();

-- h. Выполните проверку
update schema1.employees
set salary = salary * 3
where employee_id = 1;
-- триггер сработал

-- 2. Добавьте в таблицу employees 2 новых столбца:
-- a. login – для сохранения учетной записи сотрудника
-- b. password– для сохранения пароля сотрудника

alter table schema1.employees
add column login character varying,
add column password character varying;

-- 3. Создайте триггер, который будет срабатывать при добавлении или изменении
-- записей о сотрудниках:
-- a. Login и password не должны быть одинаковыми, при этом их длина должна быть
-- больше или равна 8 символов. Поля не должны содержать NULL значения.
-- b. В случае нарушения данных условий должно генерироваться пользовательское
-- исключение, предоставляющее информацию о нарушении

create function schema1.validate_employee()
returns trigger
language plpgsql
as $$
begin
if new.login is null or new.password is null then
raise exception
'поля login и password не должны быть null';
end if;

if length(new.login) < 8 or length(new.password) < 8 then
raise exception
'длина login и password должна быть не менее 8 символов';
end if;

if new.login = new.password then
raise exception
'login и password не должны совпадать';
end if;

return new;
end;
$$;
create trigger validate_employee_data
before insert or update of login, password
on schema1.employees
for each row
execute function schema1.validate_employee();

-- c. Протестируйте ваш триггер
update schema1.employees
set login = null
where employee_id = 1;

update schema1.employees
set login = '123',
password = '125678932'
where employee_id = 1;

update schema1.employees
set login = '12345678',
password = '12345678'
where employee_id = 1;

update schema1.employees
set login = 'user_login',
password = 'secure_pwd'
where employee_id = 1;

-- все работает

-- d. Удалите созданный триггер
drop trigger validate_employee_data on schema1.employees;

-- 4. Необходимо реализовать процедурную поддержку процесса карьерных
-- перемещений сотрудников - таблица job_history в схеме schema1
-- a. Таблица employees должна содержать только актуальную информацию о активных сотрудниках
-- b. Таблица job_history должна содержать информацию о всех «изменениях» сотрудника: прием,
-- увольнение, изменение должности, изменение отдела, изменение заработной платы.
-- c. Тип изменения должен сохранятся в столбце type_operation в таблице job_history

ALTER TABLE schema1.job_history
ALTER COLUMN end_date DROP NOT NULL;
ALTER TABLE schema1.job_history
ADD COLUMN location_id numeric(4,0),
ADD COLUMN type_operation text;


create or replace function schema1.employee_changes()
returns trigger
language plpgsql
as $$
declare
v_employee_id numeric(6,0);
v_job_id varchar(10);
v_department_id numeric(4,0);
v_salary numeric(10,2);
v_location_id numeric(4,0);
v_start_date date;
v_end_date date;
v_op text;
begin
if lower(tg_op) = 'insert' then
v_employee_id := new.employee_id;
v_job_id := new.job_id;
v_department_id := new.department_id;
v_salary := new.salary;
v_start_date := new.hire_date;
v_end_date := null;
v_op := 'hire';

elsif lower(tg_op) = 'update' then
if new.job_id is distinct from old.job_id then
v_op := 'job_change';
elsif new.department_id is distinct from old.department_id then
v_op := 'dept_change';
elsif new.salary is distinct from old.salary then
v_op := 'salary_change';
else
return new;
end if;

v_employee_id := new.employee_id;
v_job_id := new.job_id;
v_department_id := new.department_id;
v_salary := new.salary;
v_start_date := current_date;
v_end_date := null;

update schema1.job_history
set end_date = current_date
where employee_id = old.employee_id
and end_date is null;

elsif lower(tg_op) = 'delete' then
v_employee_id := old.employee_id;
v_job_id := old.job_id;
v_department_id := old.department_id;
v_salary := old.salary;
v_start_date := current_date;
v_end_date := current_date;
v_op := 'fire';

update schema1.job_history
set end_date = current_date
where employee_id = old.employee_id
and end_date is null;

else
return null;
end if;

select d.location_id
into v_location_id
from schema1.departments d
where d.department_id = v_department_id;

insert into schema1.job_history (
employee_id, start_date, end_date,
job_id, department_id, salary,
location_id, type_operation
)
values (
v_employee_id, v_start_date, v_end_date,
v_job_id, v_department_id, v_salary,
v_location_id, v_op
);

if lower(tg_op) = 'delete' then
return old;
end if;

return new;
end;
$$;

drop trigger if exists employee_history on schema1.employees;


create trigger employee_history
after insert or update or delete
on schema1.employees
for each row
execute function schema1.employee_changes();

select count(*) as before_cnt
from schema1.job_history
where employee_id = 1;

-- проверили кол-во строк в истории

update schema1.employees
set salary = salary + 1
where employee_id = 1;

-- сделали апдейт

select count(*) as after_cnt
from schema1.job_history
where employee_id = 1;

-- должно стать на 1 запись в истории больше

select *
from schema1.job_history
where employee_id = 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. UPDATE работает, INSERT еще не проверяла, DELETE выдает ошибку:
padii_plyugin2=> delete from schema1.employees where employee_id = 1;
ERROR:  insert or update on table "job_history" violates foreign key constraint "fk_jh_emp"
DETAIL:  Key (employee_id)=(1) is not present in table "employees".
CONTEXT:  SQL statement "insert into schema1.job_history (
        employee_id, start_date, end_date,
        job_id, department_id, salary,
        location_id, type_operation
    )
    values (
        v_employee_id, v_start_date, v_end_date,
        v_job_id, v_department_id, v_salary,
        v_location_id, v_op
    )"
PL/pgSQL function schema1.employee_changes() line 67 at SQL statement

-- проверили запись

-- все работает


-- 5. Необходимо реализовать процедурную поддержку для проверки номеров телефона
-- сотрудников на соответствие заданному шаблону. Проверка должна осуществляться как при
-- вставке новых записей о сотрудниках, так и при изменении существующих.
create function schema1.validate_phone_array()
returns trigger
language plpgsql
as $$
declare
ph phone;
begin
if new.phone_number is null or cardinality(new.phone_number) = 0 then
raise exception 'номер не должен быть null или пустым';
end if;

foreach ph in array new.phone_number loop
if ph is null then
raise exception 'номер не должен содержать null значения';
end if;
end loop;

if (select count(*) from unnest(new.phone_number) x) <>
(select count(distinct x) from unnest(new.phone_number) x) then
raise exception 'номер не должен содержать повторяющиеся номера';
end if;

return new;
end;
$$;

create trigger validate_phone_number
before insert or update of phone_number
on schema1.employees
for each row
execute function schema1.validate_phone_array();


update schema1.employees
set phone_number = '{}'::phone[]
where employee_id = 1;

update schema1.employees
set phone_number = array['8(900)000-4432','8(900)000-4432']::phone[]
where employee_id = 1;

update schema1.employees
set phone_number = array[null]::phone[]
where employee_id = 1;

update schema1.employees
set phone_number = array['8(950)111-2357','8(988)467-7000']::phone[]
where employee_id = 1;

select * from schema1.employees
where employee_id = 1;

-- все работает!