2016-04-05 21 views
5

我有一个公司拥有的电话号码表和一个电话记录表。每个呼叫记录包括(非空)源和目标号码。我被给予完整性约束,即源号码或目的号码(但不是两者)被允许为不在电话号码表中的号码(因为它们是不属于该公司的号码)。换句话说,我需要确保其中至少有一个是电话号码表的外键。SQL约束:两个属性,至少一个外键在同一个表上匹配

create table phonenumber (
    phonenum numeric(10,0) not null, 
    primary key (phonenum) 
); 
create table call_record (
    URID varchar(20) not null, 
    c_src numeric(10,0) not null, 
    c_dst numeric(10,0) not null, 
    primary key (URID) 
); 

以下听起来像什么,我想,但不是有效的SQL:

constraint call_constraint check (
    foreign key (c_src) references phonenumber (phonenum) or 
    foreign key (c_dst) references phonenumber (phonenum) 
) 

是否有DDL指定一个办法解决?如果不是,我将如何编写触发器来执行此操作?

回答

3

编辑: 下面是使用DDL和不使用触发另一个想法:

create table phonenumber (
    phonenum numeric(10,0) not null, 
    primary key (phonenum) 
); 

创建功能“手”验证外键。

CREATE OR REPLACE FUNCTION call_check(p_src NUMBER, p_dst NUMBER) RETURN VARCHAR2 DETERMINISTIC IS 
BEGIN 
    FOR x IN (SELECT COUNT(*) c 
       FROM (SELECT 1 
         FROM phonenumber 
        WHERE phonenum = p_src 
        UNION ALL 
        SELECT 1 
         FROM phonenumber 
        WHERE phonenum = p_dst)) LOOP 
    IF x.c>=1 AND x.c <= 2 THEN 
     RETURN 'OK'; 
    END IF; 
    END LOOP; 
    RETURN 'NOK'; 
END; 

如果你在11g和,然后加上虚拟列,该列

--drop table call_record 
create table call_record (
    URID varchar(20) not null, 
    c_src numeric(10,0) not null, 
    c_dst numeric(10,0) not null, 
    call_check_col GENERATED ALWAYS AS (call_check(c_src, c_dst)), 
    primary key (URID) 
); 

ALTER TABLE call_record ADD CONSTRAINT call_check_con CHECK (call_check_col='OK'); 

让我们来测试添加检查

SQL>  INSERT INTO phonenumber VALUES ('123'); 
1 row inserted 
SQL>  INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C1', '123', '321'); 
1 row inserted 
SQL>  INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C3', '123', '123'); 
1 row inserted 
SQL>  INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C2', '321', '321'); 
INSERT INTO call_record (urid, c_src, c_dst) VALUES ('C2', '321', '321') 
ORA-02290: check constraint (TST.CALL_CHECK_CON) violated 
+0

无法回到测试直到现在,但这一个工程。谢谢!我在SQL课程中,但没有讨论虚拟列。这是执行这种约束的常用方式,还是“理想”方式?我没有强烈的偏好DDL而不是触发器,但是我无论如何都不知道。 –

+0

在我看来,需要这样的约束并不常见,这可能意味着数据模型设计问题。对于触发器偏好的其他内容,我可以建议阅读“触发器是恶意的”谷歌命中。至于虚拟列,实际上你可以用它们做更多的事情,查看Oracle Magazine 2008年3月的Tom Kyte的专栏以供参考:http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28asktom -087592.html –

相关问题