SQL约束:两个属性,同一个表上至少有一个外键匹配

时间:2016-04-05 06:19:09

标签: sql oracle referential-integrity

我有一张公司拥有的电话号码表和一个电话记录表。每个呼叫记录包括(非空)源和目的地号码。我被赋予了完整性约束,即源号或目的地号码(但不是两者)都可以是不在电话号码表中的号码(因为它们不是该公司拥有的号码)。换句话说,我需要确保其中至少有一个是电话号码表的外键。

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中指定它?如果没有,我将如何编写触发器来强制执行此操作?

1 个答案:

答案 0 :(得分: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