PL / SQL触发器在Ticket表中插入行之前检查票证日期

时间:2017-09-08 05:01:19

标签: sql oracle plsql triggers

这些是我创建的表和序列,我插入了它们的值:

 CREATE TABLE Ticket_Type
  (
   t_type_id  NUMBER(1) PRIMARY KEY,
   CONSTRAINT check_t_type_id CHECK(t_type_id  > 0),
   t_type VARCHAR(20) NOT NULL,
   t_type_price NUMBER(4,2) NOT NULL,
   CONSTRAINT check_t_type_price CHECK(t_type_price > 0),
   t_type_start_date DATE NOT NULL,
   t_type_end_date DATE,
   CONSTRAINT check_t_type_end_date CHECK((t_type_end_date IS NULL) OR (t_type_end_date >= t_type_start_date)),
   CONSTRAINT unique_t_type_t_type_start_date UNIQUE(t_type,t_type_start_date)
  );


 CREATE TABLE Screening
  (
   screening_id NUMBER(6) PRIMARY KEY,
   CONSTRAINT check_screening_id CHECK(screening_id > 0),
   plan_id NUMBER(4) NOT NULL,
   theatre_id NUMBER(1) NOT NULL,
   screening_date DATE DEFAULT CURRENT_DATE NOT NULL,
   screening_start_hh24 NUMBER(2) NOT NULL,
   CONSTRAINT check_start_hh24 CHECK(screening_start_hh24 BETWEEN 9 AND 22),
   screening_start_mm60 NUMBER(2) NOT NULL,
   CONSTRAINT check_start_mm60 CHECK(screening_start_mm60 BETWEEN 0 AND 59),
   CONSTRAINT unique_theatre_id_screening_date_screening_start_hh24_screening_start_mm60 UNIQUE(theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
  );


  CREATE TABLE Ticket
  (
   ticket_id NUMBER(8) PRIMARY KEY,
   CONSTRAINT check_ticket_id CHECK(ticket_id > 0),
   t_type_id NUMBER(1) NOT NULL,
   CONSTRAINT fk_t_type_id FOREIGN KEY(t_type_id) REFERENCES Ticket_Type(t_type_id),
   screening_id NUMBER(6) NOT NULL,
   CONSTRAINT fk_screening_id FOREIGN KEY(screening_id) REFERENCES Screening(screening_id),
   seat_id NUMBER(5) NOT NULL,
   ticket_date DATE DEFAULT SYSDATE NOT NULL,
   CONSTRAINT unique_screening_id_seat_id UNIQUE(screening_id,seat_id)
  );

CREATE SEQUENCE ticket_type_seq 
START WITH 1 
INCREMENT BY 1 
NOCACHE NOCYCLE;

CREATE SEQUENCE screening_seq 
START WITH 1 
INCREMENT BY 1 
NOCACHE NOCYCLE;

CREATE SEQUENCE ticket_seq 
START WITH 1 
INCREMENT BY 1 
NOCACHE NOCYCLE;

INSERT INTO ticket_type(t_type_id,t_type,t_type_price,t_type_start_date,t_type_end_date) 
VALUES (ticket_type_seq.nextval,'Adult',13.95,to_date('1/06/2017', 'DD/MM/YYYY'),to_date('30/11/2017', 'DD/MM/YYYY'));
INSERT INTO ticket_type(t_type_id,t_type,t_type_price,t_type_start_date,t_type_end_date) 
VALUES (ticket_type_seq.nextval, 'Concession',7,to_date('1/06/2017', 'DD/MM/YYYY'),to_date('30/11/2017', 'DD/MM/YYYY'));
INSERT INTO Ticket_Type (t_type_id,t_type,t_type_price,t_type_start_date)
VALUES (ticket_type_seq.NEXTVAL,'Student',7,TO_DATE('1/6/2017','DD/MM/YYYY'));

INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,1,3,TO_DATE('11/9/2017','DD/MM/YYYY'),9,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,1,3,TO_DATE('11/9/2017','DD/MM/YYYY'),11,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,1,3,TO_DATE('11/9/2017','DD/MM/YYYY'),13,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,1,2,TO_DATE('11/9/2017','DD/MM/YYYY'),13,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,1,3,TO_DATE('11/9/2017','DD/MM/YYYY'),15,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,1,3,TO_DATE('11/9/2017','DD/MM/YYYY'),17,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,2,1,TO_DATE('11/9/2017','DD/MM/YYYY'),9,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,2,1,TO_DATE('11/9/2017','DD/MM/YYYY'),12,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,2,1,TO_DATE('11/9/2017','DD/MM/YYYY'),15,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,2,2,TO_DATE('11/9/2017','DD/MM/YYYY'),9,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,2,2,TO_DATE('11/9/2017','DD/MM/YYYY'),15,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,3,4,TO_DATE('11/9/2017','DD/MM/YYYY'),9,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,3,4,TO_DATE('11/9/2017','DD/MM/YYYY'),12,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,3,4,TO_DATE('11/9/2017','DD/MM/YYYY'),15,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,3,4,TO_DATE('11/9/2017','DD/MM/YYYY'),18,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,4,1,TO_DATE('11/9/2017','DD/MM/YYYY'),18,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,4,2,TO_DATE('11/9/2017','DD/MM/YYYY'),18,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,4,3,TO_DATE('11/9/2017','DD/MM/YYYY'),19,0);
INSERT INTO Screening (screening_id,plan_id,theatre_id,screening_date,screening_start_hh24,screening_start_mm60)
VALUES (screening_seq.NEXTVAL,4,4,TO_DATE('11/9/2017','DD/MM/YYYY'),21,0);

现在这是作业中的问题:

创建一个名为TR_valid_15_min_ticket的触发器,它应该在Ticket表中插入行之前检查ticket_date。票证发行日期(ticket_date)不能大于当前日期和时间。此外,它不能大于筛选时间+ 15分钟。否则,对于每种情况,触发器都应该引发正确的错误。错误消息必须有意义。

提示:放映时间= screening_date +(screening_start_hh24)/ 24 +(screening_start_mm60)/(24 * 60)

注意:ticket_date位于Ticket表中,screening_date,screening_start_hh24,screening_start_mm60位于筛选表中

成功编译触发器后,编写SQL语句以将数据插入表中以测试触发器。两种情况:您应该在第一天(2016年9月11日)在一个影院中插入有效和无效的票证记录。

这就是我的尝试:

CREATE OR REPLACE TRIGGER TR_valid_15_min_ticket 
BEFORE INSERT
ON Ticket
FOR
EACH ROW
DECLARE
screening_time NUMBER;
v_screening_date Screening.screening_date%TYPE;
v_screening_start_hh24 Screening.screening_start_hh24%TYPE;
v_screening_start_mm60 Screening.screening_start_mm60%TYPE;
BEGIN
SELECT screening_start_hh24,screening_start_mm60
INTO v_screening_start_hh24,v_screening_start_mm60
FROM Screening
WHERE screening_id = :NEW.screening_id;
screening_time := v_screening_date + (v_screening_start_hh24)/24 + (v_screening_start_mm60)/(24*60);
IF (:NEW.ticket_date > SYSDATE) OR  (:NEW.ticket_date > (screening_time + 15))
THEN
RAISE_APPLICATION_ERROR(-20000,'Ticket date cannot be more than the current date nor can it have extra 15 minutes with addition to its screening time');
END IF;
END;

但是,我收到以下错误:

Error(95,1): PL/SQL: Statement ignored
Error(95,19): PLS-00382: expression is of wrong type
Error(96,1): PL/SQL: Statement ignored
Error(96,55): PLS-00306: wrong number or types of arguments in call to '>'
  1. 如果提供正确的解决方案触发器代码以纠正我在代码中犯的错误,那将非常有用。

  2. 根据我使用的逻辑: IF(:NEW.ticket_date> SYSDATE)或(:NEW.ticket_date>(screening_time + 15)),我知道我必须通过使用INSERT语句在Ticket表的ticket_date列中插入有效值和无效值来测试触发器。基于(:NEW.ticket_date> SYSDATE),我已经知道我需要测试哪些无效值或有效值(:NEW.ticket_date> SYSDATE)。但是对于(:NEW.ticket_date>(screening_time + 15)),我不知道,我不确定应该输入什么无效值和有效值来测试触发器。如果基于(:NEW.ticket_date>(screening_time + 15))提供有效值和无效值,那将非常有用,这样我就可以成功测试它。

    < / LI>

1 个答案:

答案 0 :(得分:0)

演示中的错误:

CREATE TABLE Ticket_Type无效,因为CONSTRAINT unique_t_type_t_type_start_date名称太长 - 最多可包含30个字符,但长度为31个字符

CREATE TABLE Screening无法编译,因为此名称太长:ONSTRAINT unique_theatre_id_screening_date_screening_start_hh24_screening_start_mm60 UNIQUE,可以是最大值。 30个字符

此表达式会导致Error(121,19): PLS-00382: expression is of wrong type

screening_time := v_screening_date + (v_screening_start_hh24)/24 
                  + (v_screening_start_mm60)/(24*60);
  • screening_time的类型为NUMBER
  • v_screening_date的类型为DATE
  • v_screening_start_hh24的类型为NUMBER
  • v_screening_start_mm60的类型为NUMBER

DATE + NUMBER提供DATE,因此您无法将DATE值(表达式的结果)赋予NUMBER变量screening_time

这一行没有编译:

IF (:NEW.ticket_date > SYSDATE) OR  (:NEW.ticket_date > (screening_time + 15))

因为这个表达式:

:NEW.ticket_date > (screening_time + 15))
  • :NEW.ticket_date的类型为DATE
  • screening_time的类型为NUMBER

此比较 DATE&gt; NUMBER 没有任何意义,例如这个表达式应该是什么结果:2017-04-20 > 15

  

我对是否使用感到困惑:NEW.ticket_date&gt; (screening_time   + 15))或:NEW.ticket_date&gt; (screening_time +(15 * 24 * 60)))? -

尝试将这些规则分解为简单的步骤,ii将更容易理解和实现,如下例所示:

DECLARE
   .....
   .....
   condition_1 BOOLEAN;
   condition_2 BOOLEAN;
BEGIN
  ......

-- The ticket issued date (ticket_date) can not be greater than the current date and time. 
   condition_1 := :NEW.ticket_date <= SYSDATE;

-- In addition, it cannot be greater than screening time + 15 minutes. 
   condition_2 := :NEW.ticket_date <= screening_time + interval '15' minute;

-- Otherwise, for each case, the trigger should raise a proper error. 
  IF  NOT ( condition_1 AND condition_2 )
  THEN
    --   The error messages must be meaningful.
    RAISE_APPLICATION_ERROR(-20000,'Ticket date cannot be more than the current date nor can it have extra 15 minutes with addition to its screening time');
  END IF;

此外,要求为for each case, the trigger should raise a proper error.,因此每个条件都必须有两条单独的错误消息。