sql - 根据同一表中的其他数据验证插入的数据 (Oracle)

标签 sql oracle plsql triggers oracle-apex

我正在使用 SQL Oracle 做一个项目,并且发现了一个问题,因为我对 SQL 还很陌生。

我有一个系统,在一个名为“预订”的表中管理预订的房间。一些属性是:

  • room_id
  • 到达日期
  • 晚_nr
  • booking_id(即 PK)。

我有一个 UNIQUE(room_id,arrival_date) 约束。

为了拥有一个连贯的数据库,我需要检查每个插入或更新的行,该房间的任何预定预订日是否已被预订。这是基于表值的约束,我需要一个选择,因此我无法在 CHECK 中执行此操作(或者至少我还没有找到另一种可能性)。

我正在尝试使用触发器来执行此操作,但这是我第一次接触触发器。

我的想法是选择一个时间,并验证对于另一个 booking_id 和我当前打算更新的同一个 room_id,我打算预订的天数范围是否与预订的范围相交。

由于缺乏知识,我写了这样的内容:

CREATE OR REPLACE TRIGGER validate_free_room
BEFORE INSERT OR UPDATE OF arrival_date, night_nr ON bookings
FOR each row
DECLARE a char(8)
DECLARE b char(3)
SET a=booking_id
SET b=room_id
WHEN EXISTS (
    SELECT booking_id
    FROM bookings r
    WHERE 
    (r.booking_id!=a 
     AND 
     ((arrival_date BETWEEN r.arrival_date AND r.arrival_date + nights_nr)
      OR
      (arrival_date + nights_nr BETWEEN r.arrival_date AND r.arrival_date + r.nights_nr)
      )
     AND
     b=r.room_id
    )
   )
BEGIN
    RAISE_APPLICATION_ERROR (-20107,'Room already booked')
         end;

我刚刚发现我无法在使用“for every row”修改的表中执行选择。

您有什么想法我可以如何以正确的方式做到这一点? (我知道前面的句子完全是一场灾难)。

我正在使用 Oracle Application Express,它给了我以下错误建议:

ORA-24344: success with compilation error
ORA-06512: at "SYS.WWV_DBMS_SQL_APEX_190200", line 592
ORA-06512: at "SYS.DBMS_SYS_SQL", line 1658
ORA-06512: at "SYS.WWV_DBMS_SQL_APEX_190200", line 578
ORA-06512: at "APEX_190200.WWV_FLOW_DYNAMIC_EXEC", line 2057


3. for each row
4. declare a char(8)
5. declare b char(3)
6. set a=id_rezerva
7. set b=id_camera

Error computing plan for statement.
ORA-00900: invalid SQL statement

最佳答案

还有另一种不涉及触发器的方法:

  • 创建一个物化 View ,该 View 将表自身连接起来,并且仅在存在重叠时才包含行。
  • 此物化 View 应在提交时刷新。
  • 它有一个约束1=0,每次出现一行都会失败。
  • 因此,在每次提交时,如果存在重叠,则提交将失败,并且物化 View 将始终为空。

有一些 DBA 类型的事情需要完成,因此这将执行正常,例如在物化 View 日志为空时收集统计信息,然后锁定这些统计信息。

SQL> create table bookings(
  2    booking_id integer primary key,
  3    room_id integer not null,
  4    arrival_date date not null check (arrival_date = trunc(arrival_date)),
  5    nights_nr integer not null,
  6    UNIQUE(room_id, arrival_date)
  7  );

Table BOOKINGS created.

SQL> create materialized view log on bookings with rowid including new values;

Materialized view log BOOKINGS created.

SQL> create materialized view bookings_conflicts
  2  refresh fast on commit as
  3  select a.rowid arid, b.rowid brid
  4  from bookings a, bookings b
  5  where a.room_id = b.room_id 
  6    and a.arrival_date < b.arrival_date
  7    and a.arrival_date + a.nights_nr > b.arrival_date;

Materialized view BOOKINGS_CONFLICTS created.

SQL> alter materialized view bookings_conflicts add constraint no_overlaps check(1=0) deferrable;

Materialized view BOOKINGS_CONFLICTS altered.

SQL> insert into bookings
  2  select 1, 1, date '2020-01-01', 5 from dual union all
  3  select 2, 1, date '2020-01-05', 1 from dual union all
  4  select 3, 1, date '2020-01-06', 1 from dual;

3 rows inserted.

SQL> commit;

Error starting at line : 24 in command -
commit
Error report -
ORA-12008: error in materialized view or zonemap refresh path
ORA-02290: check constraint (STEW.NO_OVERLAPS) violated
....

关于sql - 根据同一表中的其他数据验证插入的数据 (Oracle),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59591274/

相关文章:

mysql - 如何计算同一条记录的不同平均值?

SQL 从时间戳差异中提取值

java - Spring JDBC 模板。如何获取 pl/sql 脚本的结果变量

oracle - 在 SQL Developer 的单元测试框架中验证 PL/SQL 存储过程 OUT REF CURSOR

sql - JPA 或数据库架构中的外键级联

sql - 如何在oracle数据库表中插入n-1列值

php - MYSQL 查询最新结果

c# - 使用 ODP.net 更新表时出现 ORA-01722 错误

java - ORA-01461-只能绑定(bind) LONG 值以插入 LONG 列

java - 从数据库表中获取结果的更好选择