完成学校作业,建立数据库。我的数据库模拟了摄影业务。大部分都很简单,但现在我被卡住了。所以在我的模型中,我有一个Photography_Availability实体(Ph_Av),每当摄影师被安排或不可用时,都会有一个相应的条目,其中包含摄影师不可用的日期和时间间隔(Available_Date,Start_Time_Available,Fin_Time_Available)。所有这些都是我的Oracle建模器中的DateTime数据类型。我想实现一个触发器,可以检查每当有人试图安排摄影师时,如果他们是否可用(在适当的日期和时间间隔内)。这是我的代码:
CREATE OR REPLACE TRIGGER SAFE_SCHEDULE
BEFORE INSERT OR UPDATE ON PH_AV
FOR EACH ROW
DECLARE
ID VARCHAR(20) := NULL;
AV_DATE DATE := NULL;
START_TIME DATE := NULL;
FIN_TIME DATE := NULL;
BEGIN
SELECT PHOTOGRAPHER_ID INTO ID FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID ;
SELECT AVAILABILITY_DATE INTO AV_DATE FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID;
SELECT START_TIME_AVAIL INTO START_TIME FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID;
SELECT FIN_TIME_AVAIL INTO FIN_TIME FROM PH_AV WHERE PHOTOGRAPHER_ID = :NEW.PHOTOGRAPHER_ID;
IF ((:NEW.START_TIME_AVAIL >= START_TIME AND :NEW.START_TIME_AVAIL <= FIN_TIME)
OR (:NEW.FIN_TIME_AVAIL >= START_TIME AND :NEW.FIN_TIME_AVAIL <= FIN_TIME)
OR (:NEW.START_TIME_AVAIL <= START_TIME AND :NEW.FIN_TIME_AVAIL >= FIN_TIME))
THEN
DBMS_OUTPUT.PUT_LINE('Cannot be scheduled, photographer unavailable');
ELSE
DBMS_OUTPUT.PUT_LINE('PHOTOGRAPHER SUCCESSFULLY SCHEDULED');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('NO DATA FOUND');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR-' || SQLERRM);
END;
/
我想要的基本逻辑是,比如摄影师已经安排在下午3点到5点之间,有人试图在下午2点到4点之间安排同一位摄影师,这显然会发生碰撞。我的if语句检查新插入的值是否与任何可能的调度值冲突。现在,在我运行之后,脚本输出并没有说明有任何错误。但我的消息日志声称相当多(其中大多数是&#34; null(内部错误)没有可投掷的堆栈元素&#34;)。
这是我第一次实现触发器,我想它可能是我声明的变量的Date数据类型,但我不知所措。有什么建议吗?
答案 0 :(得分:1)
如下所示的简单结构AVAIL
以及防止条目重叠的要求,我会做类似以下的事情:
CREATE SEQUENCE avail_sq;
CREATE TABLE avail
(
avail_id INTEGER,
person_id INTEGER,
start_dtm DATE,
end_dtm DATE
);
CREATE OR REPLACE TRIGGER test_avail_trg
FOR INSERT OR UPDATE ON avail
COMPOUND TRIGGER
TYPE avail_tt IS TABLE OF avail%ROWTYPE;
avail_t avail_tt := avail_tt();
l_cnt INTEGER;
BEFORE EACH ROW IS
BEGIN
avail_t.EXTEND;
avail_t(avail_t.COUNT).avail_id := :new.avail_id;
avail_t(avail_t.COUNT).person_id := :new.person_id;
avail_t(avail_t.COUNT).start_dtm := :new.start_dtm;
avail_t(avail_t.COUNT).end_dtm := :new.end_dtm;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
FOR i IN avail_t.FIRST..avail_t.LAST LOOP
SELECT COUNT(*)
INTO l_cnt
FROM avail a
WHERE a.person_id = avail_t(i).person_id
AND ((a.start_dtm <= avail_t(i).start_dtm AND a.end_dtm > avail_t(i).start_dtm) OR
(a.start_dtm > avail_t(i).start_dtm AND a.start_dtm < avail_t(i).end_dtm))
AND a.avail_id != avail_t(i).avail_id; -- Can't overlap itself
IF l_cnt > 0 THEN
raise_application_error(-20000, 'Overlap detected');
END IF;
END LOOP;
END AFTER STATEMENT;
END;
/
我没有从表中检索数据,而是进行了更多的存在检查。两个日期/时间过滤器检查在任何点重叠的条目。第一个检查现有条目,在新行开始之前或同时开始,在新行开始之后结束。第二个检查现有条目,这些条目在新行之后开始,也在新行结束之前开始。
因为您还允许对这些字段进行更新,所以您需要使用COMPOUND TRIGGER
,它允许您收集每行所需的数据,但也可以在语句完成后处理它们。突变已经完成。