我有一个表(a),其主要键是表(b)或表(c)的外键。

create table A (
  akey number, 
  txt varchar2(10)
);

create table B (
  bkey number, 
  txt varchar2(10)
);

create table C (
  ckey number, 
  txt varchar2(10)
);

我想要的是:

alter table A add constraint BorCkey foreign key (akey) references B(bkey)` or C(ckey);

这可能吗?

有帮助吗?

解决方案

不,在甲骨文中不可能。

您的选择通常是

  • 在bkey引用b.bkey和ckey引用c.ckey并创建一个约束条件,确保在任何时间点都不零。
  • 创建B&C具有外国关键的某种“组合的B&C”实体,并在参考该组合实体的钥匙中制作外键。

如果您想要一个约束,以确保确切的两个列之一为null,而一行均不为null

create table one_key( 
  col1 number, 
  col2 number, 
  check( nvl2(col1,1,0) + nvl2(col2,1,0) = 1 ) 
)

其他提示

外国钥匙限制是 一张外国桌子.
这意味着您需要在这种情况下使用两个Alter表语句来设置外国密钥以引用两个表。那里没有机会指定关系中的或 A.akey 两者都必须存在 B.bkey C.ckey 同时. 。例如,如果 B.bkey 具有零值,但 C.ckey 不 - 然后 A.akey 永远不会有零值。外键在Oracle中是延迟的,但是所描述的行为是同时启用两个外键的行为 - 如果所有值不满足关系,则将无法启用约束。

您需要查看如何简化关系的需求,因此它不需要两个表即可完成这项工作。

听起来您有某种形式的亚型/超级型关系。一个典型的例子是“人”,它可能是“客户”或“供应商”。

您可能在人表中拥有person_id的唯一键以及person_type('cust'或'supp')的属性。如果您在person_id上创建主键,则Person_Type可以在子类型表(供应商/客户)中引用该键。

然后,您对Person_ID添加了唯一的约束,以确保Person_ID的任何值必须是客户或供应商,而不是两者兼而有之,并检查子类型表上的约束,以便表中仅表示一种类型。

create table person
  (person_id     number,
   person_type   varchar2(4),
   name          varchar2(10),
    constraint person_pk primary key (person_id, person_type),
    constraint person_id_uk unique (person_id));

create table supplier
  (supplier_id   number,
   supplier_type varchar2(4),
   blah          varchar2(10),
  constraint supplier_pk primary key (supplier_id, supplier_type),
  constraint supp_pers_fk foreign key  (supplier_id, supplier_type)
    REFERENCES person (person_id, person_type)
  )
/
alter table supplier add constraint supp_type_ck check (supplier_type = 'SUPP');

它不是很漂亮,但是类型/子类型更像是对象概念,而不是关系概念。

我的解决方案受贾斯汀的启发:

CREATE OR REPLACE TRIGGER abc
  BEFORE INSERT OR UPDATE ON a
  FOR EACH ROW
  DECLARE
  v_testB NUMBER:= 0;
  v_testC NUMBER:= 0;
  BEGIN
    SELECT
      COUNT(bkey)
    INTO
      v_testB
    FROM
      b
    WHERE
      bkey = :new.aKey;
    SELECT
      COUNT(ckey)
    INTO
      v_testC
    FROM
      c
    WHERE
      ckey = :new.aKey;
    IF ((v_testB + v_testC) <> 1) THEN
      RAISE_APPLICATION_ERROR(-20002,'Foreign key to B or C missing.');
    END IF;
  END;
/
SHOW ERRORS TRIGGER abc

创建一个实体的观点,即工会表B&C,并将您的FK限制指向视图

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top