2016-06-09 120 views
0

需要你的帮助交叉表数据验证

我有2个连接的实体:库读者(订户)和书的问题。读者可以在因为破坏图书馆的规定天被锁定一段时间:

DB logical scheme

我需要补充检查,以便读者,谁的锁定期尚未结束,不能拿一本书在库(换句话说,Issue.Taken> Subscriber.Lock_Date + Subscriber.Lock_Period)

请帮忙,我该怎么做?

回答

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 

如果条件不满足,则没有内容,将引发异常,其中触发器将什么也不做,行将被插入。

+0

它适用于在表中插入新行,但是当我尝试返回书籍(或任何其他更新)时,我得到ORA-04091表是变异错误。我能绕过这个错误还是触发限制? – JGDger

+0

但触发器只能在插入时触发。它在更新上发射吗? –

+0

是的,错误引发更新,我不明白为什么 – JGDger

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); 
+0

尝试它,但尝试创建物化视图时出现错误:ORA 00439 - 功能未启用:高级复制。这是否意味着由于某种原因我无法创建物化视图? – JGDger

+0

你可以但是你不能使用日志或'FAST REFRESH ON COMMIT' ......这意味着它可以工作,但是你必须通过另一种方法保持物化视图的更新 - 这会使它变得不切实际。 – MT0

+0

正如我在第一行中所说 - 在表级解决这个问题是可能的,但不是最好的解决方案。更好的解决方案是只允许通过程序(或用于访问oracle的中间层的业务逻辑)取出书籍,然后包装检查用户没有被锁定的所有业务逻辑。 – MT0