Добавил:
t.me Прошиваю/настраиваю роутеры в общаге МИЭТ, пишите в тг: t.me/aogudugnp Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
отчеты по лабам / СУБД_ЛР6_вар3.docx
Скачиваний:
0
Добавлен:
21.06.2025
Размер:
1.69 Mб
Скачать
  1. Практическая часть Задание 1.

Напишите SQL запросы к учебной базе данных в соответствии с вариантом. Вариант к практической части выбирается по формуле: V = (N % 10) +1, где N – номер в списке группы, % - остаток от деления.

№ варианта

№ запросов

3

3, 13, 23, 33, 43, 53, 63

Сборник запросов к учебной базе данных

Скрипты на языке PL/pgSQL

  1. Напишите скрипт, формирующий таблицу со средним баллом по каждой дисциплине у преподавателей Института МПСУ

SELECT

p.last_name ||' '|| p.first_name ||' '|| p.patronymic AS professor_name,

f.field_name,

AVG(f.zet) AS average_grade

FROM

professors p

JOIN

employments e ON p.professor_id = e.professor_id

JOIN

fields f ON e.structural_unit_id = f.structural_unit_id

JOIN

field_comprehensions fc ON f.field_id = fc.field

WHERE

e.structural_unit_id = 1 -- Здесь 1 соответствует Институту МПСУ

GROUP BY

p.last_name, p.first_name, p.patronymic, f.field_name;

  1. Напишите скрипт, который случайным образом разбивает студентов на пары для вальса (мальчик/девочка). Мальчикам, которым не хватило пары в поле партнерши поставить значение «Teddy bear :(»

ALTER TABLE students ADD COLUMN IF NOT EXISTS partner TEXT;

UPDATE students

SET partner = NULL;

CREATE TEMPORARY TABLE temp_pairs AS

WITH boys AS (

SELECT student_id, first_name, last_name, ROW_NUMBER() OVER (ORDER BY RANDOM()) AS row_num

FROM students

WHERE

(patronymic IS NOT NULL AND patronymic LIKE '%ч')

OR (patronymic IS NULL AND last_name !~ '[аеёиоуыэюя]$')

),

girls AS (

SELECT student_id, first_name, last_name, ROW_NUMBER() OVER (ORDER BY RANDOM()) AS row_num

FROM students

WHERE

(patronymic IS NOT NULL AND patronymic LIKE '%а')

OR (patronymic IS NULL AND last_name ~ '[аеёиоуыэюя]$')

)

SELECT

b.student_id AS boy_id,

b.first_name AS boy_first_name,

b.last_name AS boy_last_name,

g.student_id AS girl_id,

g.first_name AS girl_first_name,

g.last_name AS girl_last_name

FROM boys b

LEFT JOIN girls g ON b.row_num = g.row_num;

UPDATE students s

SET partner = COALESCE(

(SELECT p.girl_first_name || ' ' || p.girl_last_name

FROM temp_pairs p

WHERE p.boy_id = s.student_id),

'Teddy bear :('

)

WHERE s.student_id IN (SELECT boy_id FROM temp_pairs);

UPDATE students s

SET partner = COALESCE(

(SELECT p.boy_first_name || ' ' || p.boy_last_name

FROM temp_pairs p

WHERE p.girl_id = s.student_id),

'Teddy bear :('

)

WHERE s.student_id IN (SELECT girl_id FROM temp_pairs WHERE girl_id IS NOT NULL);

DROP TABLE temp_pairs;

  1. Создайте процедуру увеличения зарплаты преподавателя в зависимости от стажа. Стаж до 10 лет – увеличиваем на a, от 11 до 20 – на 2a, более на 3a рублей. Где a входной параметр процедуры

CREATE OR REPLACE PROCEDURE increase_salary(

p_professor_id INT,

a NUMERIC -- New parameter for the salary increase amount

)

LANGUAGE plpgsql

AS $$

DECLARE

v_experience INT;

v_current_salary NUMERIC;

BEGIN

-- Получаем стаж и текущую зарплату преподавателя

SELECT

experience, salary

INTO

v_experience, v_current_salary

FROM

professors

WHERE

professor_id = p_professor_id;

-- Проверяем, существует ли преподаватель

IF NOT FOUND THEN

RAISE EXCEPTION 'Professor with ID % not found', p_professor_id;

END IF;

-- Увеличиваем зарплату в зависимости от стажа

IF v_experience < 10 THEN

v_current_salary := v_current_salary + a;

ELSIF v_experience >= 10 AND v_experience <= 20 THEN

v_current_salary := v_current_salary + 2 * a;

ELSE

v_current_salary := v_current_salary + 3 * a;

END IF;

-- Обновляем зарплату в таблице

UPDATE professors

SET salary = v_current_salary

WHERE professor_id = p_professor_id;

RAISE NOTICE 'Salary for professor ID % updated to %', p_professor_id, v_current_salary;

END;

$$

--вызов процедуры для конкретного препода

CALL increase_salary(id, salary); --

  1. Создайте функцию, которая определяет разницу в возрасте между двумя студентами

CREATE OR REPLACE FUNCTION age_difference(student_id1 INT, student_id2 INT)

RETURNS INT AS $$

DECLARE

birthday1 DATE;

birthday2 DATE;

age_diff INT;

BEGIN

-- Получаем даты рождения двух студентов

SELECT birthday INTO birthday1 FROM students WHERE student_id = student_id1;

SELECT birthday INTO birthday2 FROM students WHERE student_id = student_id2;

-- Проверка на существование студентов

IF birthday1 IS NULL OR birthday2 IS NULL THEN

RAISE EXCEPTION 'One or both student IDs do not exist.';

END IF;

-- Вычисляем разницу в возрасте

age_diff := EXTRACT(YEAR FROM AGE(birthday1)) - EXTRACT(YEAR FROM AGE(birthday2));

-- Возвращаем абсолютное значение разницы

RETURN ABS(age_diff);

END;

$$ LANGUAGE plpgsql;

SELECT age_difference(1, 2);

  1. Создайте функцию, рассчитывающую среднюю зарплату преподавателей в каждом структурном подразделении

CREATE OR REPLACE FUNCTION calculate_department_median_salaries()

RETURNS TABLE (

department_id INTEGER,

department_name TEXT,

median_salary NUMERIC

) AS $$

BEGIN

RETURN QUERY

WITH ranked_salaries AS (

SELECT

su.structural_unit_id,

su.full_title,

(p.salary::NUMERIC) AS salary_amount,

ROW_NUMBER() OVER (PARTITION BY su.structural_unit_id ORDER BY (p.salary::NUMERIC)) AS row_num,

COUNT(*) OVER (PARTITION BY su.structural_unit_id) AS total_count

FROM

Structural_units su

JOIN

Employments e ON su.structural_unit_id = e.structural_unit_id

JOIN

Professors p ON e.professor_id = p.professor_id

)

SELECT

rs.structural_unit_id AS department_id,

rs.full_title AS department_name,

AVG(rs.salary_amount) AS median_salary

FROM

ranked_salaries rs

WHERE

rs.row_num IN (rs.total_count/2, (rs.total_count+1)/2)

GROUP BY

rs.structural_unit_id, rs.full_title

ORDER BY

rs.structural_unit_id;

END;

$$ LANGUAGE plpgsql;

  1. Создайте триггер, который запрещает добавление и изменение даты выдачи студенческого билета, у которого дата выдачи> даты по которую он действителен.

-- 1. Создаем функцию триггера

CREATE OR REPLACE FUNCTION check_issue_date()

RETURNS TRIGGER AS $$

BEGIN

-- Проверяем, что дата выдачи не превышает дату окончания действия

IF NEW.issue_date > NEW.expiration_date THEN

RAISE EXCEPTION 'Дата выдачи не может быть больше даты окончания действия';

END IF;

RETURN NEW; -- Возвращаем новую запись

END;

$$ LANGUAGE plpgsql;

-- 2. Создаем триггер

CREATE TRIGGER issue_date_trigger

BEFORE INSERT OR UPDATE ON student_ids

FOR EACH ROW

EXECUTE FUNCTION check_issue_date();

INSERT INTO student_ids (student_id, issue_date, expiration_date)

VALUES (1, '2025-01-01', '2024-12-31'); -- Это вызовет ошибку

UPDATE student_ids

SET issue_date = '2028-01-01'

WHERE student_id = 863954;

  1. Создайте триггер, не позволяющий вводить дубли в таблицу студентов (совпадение фамилии, имени и отчества с точностью до двух букв в каждом). В предупреждении выведите ФИО студента с похожими данными. Используйте функцию levenshtein().

CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;

CREATE OR REPLACE FUNCTION prevent_similar_students()

RETURNS TRIGGER AS $$

DECLARE

similar_student RECORD;

error_message TEXT;

BEGIN

SELECT INTO similar_student s.*

FROM Students s

WHERE

levenshtein(lower(NEW.last_name), lower(s.last_name)) <= 2 AND

levenshtein(lower(NEW.first_name), lower(s.first_name)) <= 2 AND

(

(NEW.patronymic IS NULL AND s.patronymic IS NULL) OR

(NEW.patronymic IS NOT NULL AND s.patronymic IS NOT NULL AND

levenshtein(lower(NEW.patronymic), lower(s.patronymic)) <= 2)

)

LIMIT 1;

IF FOUND THEN

error_message := format(

'Cannot insert student: similar student already exists (ID: %s, Name: %s %s %s)',

similar_student.student_id,

similar_student.last_name,

similar_student.first_name,

COALESCE(similar_student.patronymic, '')

);

RAISE EXCEPTION '%', error_message;

END IF;

RETURN NEW;

END;

$$ LANGUAGE plpgsql;

CREATE TRIGGER check_similar_students

BEFORE INSERT OR UPDATE ON Students

FOR EACH ROW EXECUTE FUNCTION prevent_similar_students();

INSERT INTO students (student_id, last_name, first_name, patronymic, students_group_number, birthday, email, partner)

VALUES ('863954', 'Жадов', 'Василий', 'Николаич', 'ИТД-42', '2000-01-01', 'email@example.com', NULL);

Соседние файлы в папке отчеты по лабам