Передайте вставленный параметр в функцию триггера - PullRequest
0 голосов
/ 28 марта 2019

Я пытаюсь создать функцию / триггер, который работает между двумя таблицами, курсами и зачислением, используя postgresql.Когда в таблицу регистрации добавляется новая строка, триггер должен обновить соответствующее зарегистрированное значение в таблице курсов и установить для открытой статистики значение false, если оно заполнено.

Я пытался выбрать соответствующий курс иззарегистрируйте таблицу и обновите соответствующую таблицу, используя следующие коды:

Таблицы:

create table students (
    id integer primary key,
    name varchar(24)
);

create table courses (
    num varchar(6) primary key,
    open boolean not null,
    enrolled integer default 0,
    lim integer default 3
);


create table enrollment (
    student integer references students(id),
    course varchar(6) references courses(num)
);

Функция и триггер:

create or replace function func_1() returns trigger as
  $$
  declare
    enrol integer;
    limt integer;
  begin
        select enrolled into enrol from courses where num = (select course from enrollment where course = new.course);
        select lim into limt from courses where num = (select course from enrollment where course = new.course);
        if enrol<limt then
            update courses set enrolled = enrol+1 where num = (select course from enrollment where course = new.course);
            if enrol = limt-1 then
                update courses set open = False where num = (select course from enrollment where course = new.course);
            end if;
        end if;
        return new;
  end;
  $$ language plpgsql;

create trigger trigger_1
  after insert
  on enrollment
  execute procedure func_1();

Предположим, что следующие данные были вставлены втаблица студентов и курсов:

insert into students values(1, 'Alice');
insert into students values(2, 'Bob');
insert into courses values('CS1555', True);
insert into courses values('CS1501', True);

Когда я запускаю это:

insert into enrollment values(1, 'CS1501');

Он вставляется в таблицу регистрации, но не обновляет соответствующие строки в таблице курсов, зачисленные оцениваютсяне получил + 1.

Я также попытался заменить

where num = (select course from enrollment where course = new.course)

на

where num in (select course from enrollment)

в триггере, но если я это сделаю, он обновит всестроки в таблице курсов (все зарегистрированные значения получили +1), а не соответствующие.

Пожалуйста, дайте мне знать, как я могу правильно обновить соответствующие значения, спасибо!

1 Ответ

1 голос
/ 28 марта 2019

Перво-наперво: студент не должен иметь возможность записаться несколько раз на один и тот же курс + нет смысла, чтобы студент записывался на какой-либо курс или нулевой студент на курс (если у вас нет веских причин дляэто).
UNIQUE + NOT NULL подлежит определению.Давайте использовать primary key.

create table enrollment (
    student integer references students(id),,
    course varchar(6) references courses(num),
    PRIMARY KEY (student, course)
);

С точки зрения нормализации БД ваш подход не годится: enrolled не зависит (только) от ключа.
Лучшее решение - это рассчитатьit:

SELECT courses.*,
(SELECT COUNT(*) FROM enrollment WHERE enrollment.course = courses.num) AS enrolled
FROM courses

Кроме того, вы можете выполнить вставку и обновить таблицу в 1 выражении:

WITH InsertStatement AS (
INSERT INTO enrollment VALUES(1, 'CS1501')
RETURNING course
)
UPDATE courses
SET enrolled = enrolled + AddedStudents
FROM (SELECT course, count(*) AS AddedStudents FROM InsertStatement GROUP BY course) Aux
WHERE courses.num = Aux.course

Я могу немного рассказать о том, почему ваш триггер не работает.
Поведение по умолчанию для триггера должно выполняться после каждого оператора.Для вашего кода необходимо указать FOR EACH ROW.

Переопределить триггер и посмотреть, решит ли он вашу проблему.Тем не менее, я НЕ гарантирую, что это будет работать с одновременными вставками (именно поэтому 80% моего ответа о том, чтобы избежать использования триггера).

...