跨表数据验证

时间:2016-06-09 22:45:55

标签: sql oracle erwin

需要你的帮助

我有2个连接的实体:图书馆读者(订阅者)和图书问题。由于违反了库规则,读者可以在几天内锁定一段时间:

DB logical scheme

我需要添加支票,以便读者的锁定时间尚未结束,无法在图书馆中取书(换句话说,问题与拍摄>订阅者。 Lock_Date + Subscriber.Lock_Period)

请帮忙,我该怎么做?

2 个答案:

答案 0 :(得分:3)

这应该在业务逻辑中处理,而不是在表级处理。

但是,您可以使用物化视图来执行此操作:

CREATE TABLE subscriber (
  id          INT PRIMARY KEY,
  lock_date   DATE,
  lock_period INTERVAL DAY(5) TO SECOND
);

CREATE TABLE issue (
  id        INT PRIMARY KEY,
  subscr_id INT NOT NULL REFERENCES subscriber( id ),
  book_id   INT,
  taken     DATE,
  returned  DATE
);

CREATE MATERIALIZED VIEW LOG ON subscriber
   WITH SEQUENCE, ROWID( id, lock_date, lock_period )
   INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW LOG ON issue
   WITH SEQUENCE, ROWID( subscr_id, taken )
   INCLUDING NEW VALUES;

CREATE MATERIALIZED VIEW subscriber_issue_MV
   BUILD IMMEDIATE
   REFRESH FAST ON COMMIT
   AS SELECT s.id,
             s.lock_date,
             s.lock_period,
             i.taken
      FROM   subscriber s
             INNER JOIN
             issue i
             ON ( i.subscr_id = s.id );

ALTER TABLE subscriber_issue_MV ADD CONSTRAINT subscriber_issue__mv__chk
  CHECK (   lock_date   IS NULL
         OR lock_period IS NULL
         OR NOT taken BETWEEN lock_date AND lock_date + lock_period );

答案 1 :(得分:1)

我同意MTO的观点,即应通过应用程序代码(通过存储过程)处理此类验证。但是,如果您坚持通过数据库执行此验证,则以下触发器将有所帮助。同样,我不建议使用此解决方案,最好的方法是使用应用程序逻辑来处理它。

CREATE OR REPLACE TRIGGER trg_val_lock_dt
BEFORE INSERT ON issue
FOR EACH ROW
DECLARE
    v_is_valid CHAR(1);
BEGIN

    v_is_valid := 'Y';

    SELECT 'N' INTO v_is_valid 
    FROM subscriber s
    WHERE :NEW.subscr_id = s.subscr_id
    AND :NEW.taken BETWEEN s.lock_date AND (s.lock_date + lock_period);

    RAISE_APPLICATION_ERROR(-20001,'The subscriber is locked'); 

EXCEPTION
    WHEN NO_DATA_FOUND THEN
       NULL;
END;

上述触发器将在问题表中的每次插入之前触发。它将检查所采取的日期是否在锁定日期和锁定日期+锁定期间(这将是锁定结束日期)之间。如果找到这样的记录,那么它将抛出以下错误,并且不会插入该行。

ORA-20001: The subscriber is locked
ORA-06512: at "RETAIL_1.TRG_VAL_LOCK_DT", line 12

如果条件不满足,则会引发无数据发现异常,触发器将不执行任何操作并插入行。