如何在触发器中指定if语句?

时间:2014-12-05 16:45:30

标签: sql postgresql plpgsql

我需要插入一个"考试题目"排成一张桌子。

但是,如果学生(由学生编号sno识别)已经进入该考试(由考试代码excode识别),则无法插入考试条目,如果学生有多个条目,也无法插入该条目同一天的考试(我有一个考试表,其中包含考试日期的信息)。

我相当确定我应该使用插入触发器功能并且一直在查看:

{39}来自http://www.postgresql.org/docs/9.2/static/plpgsql-trigger.html

到目前为止,我有:

INSERT INTO
entry(excode, sno, egrade) VALUES (2, 1, 98.56)

CREATE FUNCTION  entry_insert() RETURNS trigger AS $entry_insert$
BEGIN
--Check student is not entered into same exam twice
IF BLA BLA

RAISE EXCEPTION 'A student cannot be be entered into the same exam more than once'; 
END IF;
--Check student not taking more than one exam on same day
IF BLA BLA

RAISE EXCEPTION 'A student cannot take more than one exam on the same day';
END IF;

END;
$entry_insert$ LANGUAGE PLPGSQL;

CREATE TRIGGER entry_insert BEFORE INSERT ON entry
FOR EACH ROW EXECUTE PROCEDURE entry_insert();

我放置bla bla的地方是我需要的条件,我无法弄清楚如何满足我的条件。

会喜欢一些帮助吗?

编辑:我的考试表

CREATE TABLE exam (
excode       CHAR(4) NOT NULL PRIMARY KEY,
extitle      VARCHAR(20) NOT NULL,
exlocation   VARCHAR(20) NOT NULL, --I'm assuming that an exam will have a location confirmed prior to insertion into the table--
exdate       DATE NOT NULL
        CONSTRAINT incorrectDate
        CHECK (exdate >='01/06/2015' AND  exdate <= '30/06/2015'),  /* I'm assuming that all exams must have a date confirmed or otherwise the exam wouldn't be inserted into the table*/
extime       TIME NOT NULL, -- I'm assuming that an exam will have a time confirmed prior to insertion into the table--
        CONSTRAINT incorrect_time 
        CHECK (extime BETWEEN '09:00:00' AND '18:00:00')
);

1 个答案:

答案 0 :(得分:1)

您不需要为此使用触发器,您可以使用普通表约束,但您需要定义一个函数。

您的第一个要求 - 同一个学生不能两次进入同一个考试 - 可以使用UNIQUE约束(excode,sno)进行检查。从理论上讲,这种检查是多余的,因为第二次检查(学生每天不能参加一次以上的检查)也会受到违反。但是,为了满足后续记录更新的可能性,仍然需要此UNIQUE约束。

使用CHECK约束可以满足第二个要求。但是,您必须创建一个函数,因为无法在CHECK约束中使用子查询。

以下是一个例子:

-- Assume we have an exams table. This table specifies the time of each exam
CREATE TABLE exams(excode SERIAL PRIMARY KEY, extime timestamp);

-- Create the entry table. We cannot add the CHECK constraint right away
-- because we have to define the function first, and the table must exist
-- before we can do that.
CREATE TABLE entry(excode int, sno int, egrade FLOAT, UNIQUE(excode,sno));

-- Create a function, which performs a query to return TRUE if there is
-- another exam already existing which this student is enrolled in that
-- is on the same day as the exame identified with p_excode
CREATE FUNCTION exam_on_day(p_excode int, p_sno int) RETURNS bool as $$
SELECT TRUE 
FROM entry 
    LEFT JOIN exams ON entry.excode=exams.excode 
WHERE sno=p_sno AND entry.excode != p_excode
    AND date_trunc('day',extime)=(
        SELECT date_trunc('day', extime) FROM exams WHERE excode=p_excode
    );
$$ LANGUAGE SQL;

-- Add check constraint
ALTER TABLE entry ADD CONSTRAINT exam_on_same_day 
    CHECK(not exam_on_day(excode, sno));

-- Populate some exames.
-- excode 1
INSERT INTO exams(extime) VALUES('2014-12-06 10:00');
-- excode 2
INSERT INTO exams(extime) VALUES('2014-12-06 15:00');
-- excode 3
INSERT INTO exams(extime) VALUES('2014-12-05 15:00');

现在我们可以尝试一下:

harmic=> INSERT INTO entry(excode,sno,egrade) VALUES(1,1,98.5);
INSERT 0 1

harmic=> INSERT INTO entry(excode,sno,egrade) VALUES(1,1,50);
ERROR:  duplicate key value violates unique constraint "entry_excode_sno_key"
DETAIL:  Key (excode, sno)=(1, 1) already exists.

harmic=> INSERT INTO entry(excode,sno,egrade) VALUES(2,1,99);
ERROR:  new row for relation "entry" violates check constraint "exam_on_same_day"
DETAIL:  Failing row contains (2, 1, 99).

harmic=> INSERT INTO entry(excode,sno,egrade) VALUES(3,1,75);
INSERT 0 1

harmic=> UPDATE entry SET egrade=98 WHERE excode=1 AND sno=1;
UPDATE 1

test=> UPDATE entry SET excode=2 WHERE excode=3 AND sno=1;
ERROR:  new row for relation "entry" violates check constraint "exam_on_same_day"
DETAIL:  Failing row contains (2, 1, 75).

请注意,我有意义地命名了约束,因此当您收到错误时,您可以看到原因(如果您有多个约束,则非常有用)。

另请注意,用于SELECT约束的函数会从检查中排除正在更新的记录(entry.excode != p_excode),否则您无法更新任何记录。

当然,你仍然可以使用触发器执行此操作,尽管设置起来会不必要地复杂化。 IF条件与上面创建的函数类似。