检查costraint(或更好的东西)

时间:2018-07-05 19:52:03

标签: java sql oracle plsql constraints

情况:有一个Java应用程序从DB Oracle中读取数据。为简化起见,当前从“ USERS”表中读取电子邮件字段。现在,我必须修改该应用程序,以便可以阅读更多电子邮件地址,但是我无意修改引用此表的所有数十种现有查询。防范措施是添加一个“ EMAILS”表,该表仅包含“ id_user”和“ mail_address”字段(除PK“ id_mailaddr”外)。但是,由于数据不仅是由应用程序加载的,而且还由其他用户通过多种方法(Excel表,查询“全部插入”,sql loader等)加载的,因此我必须在数据库级别施加一致性条件。问题就在这里!我不知道Oracle和Pl-sql。如果我在新表中插入的电子邮件地址的“ id_user”已经存在于“ USERS”表中,那么我该如何写一个“检查”约束来强加该“ id_user”的电子邮件地址表“ USERS”必须与新表中匹配的表一致吗?
例如:

USERS                                     EMAILS
id_user  user       email                 id_mailaddr   id_user  mail_address
100      Smith      smith@yahoo.com       1             100      smith@yahoo.com        OK!
101      Brown      brown@gmail.com       2             101      brown@gmail.com        OK!
102      M.Scott                          3             105      scott@hotmail.com      NO!
103      J.Scott    scott@hotmail.com     4             103      j_scott@hotmail.com    NO!
104      P.Scott                          5             104      scotty@aol.com         OK!

2 个答案:

答案 0 :(得分:0)

希望此触发代码有帮助-

drop table users;
drop table email;

CREATE TABLE users
    (id_user integer, userz varchar2(7), email varchar2(17))
;

INSERT ALL 
    INTO users (id_user, userz, email)
         VALUES (100, 'Smith', 'smith@yahoo.com')
    INTO users (id_user, userz, email)
         VALUES (101, 'Brown', 'brown@gmail.com')
    INTO users (id_user, userz, email)
         VALUES (102, 'M.Scott', '')
    INTO users (id_user, userz, email)
         VALUES (103, 'J.Scott', 'scott@hotmail.com')
    INTO users (id_user, userz, email)
         VALUES (104, 'P.Scott', '')
SELECT * FROM dual
;



CREATE TABLE email
    (id_mailaddr int, id_user int, mail_address varchar2(19))
;


insert INTO email (id_mailaddr, id_user, mail_address)
         VALUES (3, 105, 'scott@hotmail.com');

insert INTO email (id_mailaddr, id_user, mail_address)
         VALUES (5, 104, 'scotty@aol.com');         

create or replace trigger email_trig
after insert on email
for each row
declare
v_cnt integer := 0;
mail_adr varchar2(64);
e exception;
begin
    if inserting then
        select email, count(*) into mail_adr, v_cnt from users where id_user = :new.id_user group by email;

        if v_cnt = 0 or mail_adr <> :new.mail_address then
            raise e;
        end if;
    end if;
exception
    when others then
        raise_application_error(-20000, 'Error inserting new email:- '||:new.mail_address);
end;
/

答案 1 :(得分:0)

如果我的理解正确,那么您要确保没有将id_usermail_address组合插入到先前存在的{{1}中不存在的新EMAILS表中}表?

这仅在临时设计时才有意义,因为对于任何给定的USERS记录,您最多只能放置一个EMAIL记录。 (我假设USERS中的行必须是唯一的。)

但是,如果那是随身携带的东西(为此+1,喜欢它!),我认为您在说的是外键约束

EMAILS

这将确保没有任何alter table users add constraint users_id_email_u1 UNIQUE (id_user, email); alter table emails add constraint user_id_email_f1 FOREIGN KEY ( id_user, mail_address) REFERENCES users ( id_user, email); 行与EMAILS中的行不匹配。

但是,它不能确保相反!也就是说,可能有USERS行在USERS中没有必要的行。我认为您在帖子中没有询问过该案件,但我认为这可能对您很重要。因此,我建议您确实要做的是:

EMAILS

...,并且可能处理插入到CREATE OR REPLACE VIEW emails AS SELECT id_user, email mail_address FROM users; “表”中的内容...

EMAILS

然后,将所有查询升级为使用CREATE OR REPLACE TRIGGER emails_trg INSTEAD OF INSERT ON emails FOR EACH ROW BEGIN UPDATE users SET email = :new.mail_address WHERE id_user = :new.id_user; END; 后,将视图替换为真实表。