将插入的参数传递给触发函数

时间:2019-03-28 00:20:12

标签: sql postgresql plpgsql

我正在尝试使用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);

已将其插入到注册表中,但不会更新课程表中的相应行,注册的值未获得+1。

我也试图替换

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

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

在触发器中,但是如果我这样做了,它将更新课程表中的所有行(所有注册值都为+1),而不是相应的行。

请让我知道如何正确更新相应的值,谢谢!

1 个答案:

答案 0 :(得分:1)

第一件事:学生不应多次报名参加同一门课程,而让学生报名不参加课程或空学生报名参加课程是没有意义的(除非您有充分的理由它)。
STOSB + UNIQUE要定义。让我们使用NOT NULL

primary key

就数据库规范化而言,您的方法不好:create table enrollment ( student integer references students(id),, course varchar(6) references courses(num), PRIMARY KEY (student, course) ); 不(仅)依赖于密钥。
最好的解决方案是计算它:

enrolled

或者,您可以在1条语句中进行插入和更新表:

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

我可以详细说明一下您的触发器为何不起作用。
trigger的默认行为是在每个语句之后执行。您的代码要求指定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

重新定义触发器,看看它是否可以解决您的问题。但是,我保证此操作对并发插入有效(这就是为什么我的答案中有80%是关于避免使用triger的。)