ORACLE:比较两个值PL / SQL

时间:2012-11-20 21:46:22

标签: oracle

您好我有以下脚本

CREATE OR REPLACE TRIGGER DOUBLE_BOOKINGS
BEFORE INSERT OR UPDATE ON BOOKING_SESSION
FOR EACH ROW
DECLARE
    session_date TIMESTAMP;
    session_room NUMBER;
BEGIN
    SELECT start_session
        INTO session_date --- EXISTING SESSION
        FROM booking_session
    WHERE bk_room = :NEW.bk_room;
    IF session_date = :NEW.start_session THEN
    RAISE_APPLICATION_ERROR
    (-1000, 'Room is already booked');
    END IF;
END;
/

该脚本可以将任何新预订与同一房间和同一日期的现有预订相匹配(以停止双重预订)

然而它无法正常工作。

SQL> INSERT INTO BOOKING_SESSION VALUES (45,TO_TIMESTAMP('18/03/2012 10:00', '
INSERT INTO BOOKING_SESSION VALUES (45,TO_TIMESTAMP('18/03/2012 10:00', 'DD/MM
            *
ERROR at line 1:
ORA-04098: trigger 'U1146815.ROOM_BOOKED' is invalid and failed re-validation

start_session是数据库列名,我在其中存储预订的日期和时间,并且是时间戳。 booking_session是保存预订的名称,bk_room保留了房间的数量。

因此,在提交预订之前,我尝试将new预订日期与同一房间的旧预订日期相匹配,然后显示错误消息。

更新

新错误,似乎是返回太多行,我怎么能一次做一个。

ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "U1146815.DOUBLE_BOOKINGS", line 5
ORA-04088: error during execution of trigger 'U1146815.DOUBLE_BOOKINGS'

2 个答案:

答案 0 :(得分:0)

您显然在ROOM_BOOKED表上有另一个名为BOOKING_SESSION的触发器。并且该触发器处于无效(未编译)状态。

如果您只想阻止具有重复bk_room / start_session值的记录,只需向表中添加唯一约束:

ALTER TABLE booking_session
add CONSTRAINT my_constraint UNIQUE (bk_room, start_session);

编辑:您的新错误是因为您在表中具有相同bk_room值的多个记录,这是预期的。但是,正如我在上面所述,你不需要触发器来防止重复,只需要一个独特的约束。

答案 1 :(得分:0)

如果在代码中使用SELECT...INTO,则select必须返回一行。在其他情况下,它会抛出NO_DATA_FOUND异常或TOO_MANY_ROWS(您的情况)。您可以捕获这些异常,但它可能会使代码不清楚。最好使用光标来查询你的记录。

试试这个

CREATE OR REPLACE TRIGGER DOUBLE_BOOKINGS
BEFORE INSERT OR UPDATE ON BOOKING_SESSION
FOR EACH ROW
DECLARE
    session_date TIMESTAMP;
    session_room NUMBER;
    CURSOR c_existing IS
        SELECT start_session
            FROM booking_session
        WHERE bk_room = :NEW.bk_room and
              session_date = :NEW.start_session;
    dummy_session c_existing.start_session%TYPE;
BEGIN
    OPEN c_existing;
    FETCH c_existing INTO dummy_session;
    IF c_existing%FOUND THEN
       CLOSE c_existing;
       RAISE_APPLICATION_ERROR
          (-1000, 'Room is already booked');
    END IF;
    CLOSE c_existing;
END;

/