我需要插入一个"考试题目"排成一张桌子。
但是,如果学生(由学生编号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')
);
答案 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条件与上面创建的函数类似。