Question

I ai une table (A) dont la clé primaire est soit une clé étrangère à la table (B) ou de la table (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)
);

Ce que je veux est quelque chose comme:

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

Est-ce possible?

Était-ce utile?

La solution

Non, ce genre de chose est impossible dans Oracle.

Vos options sont généralement

  • Créez deux colonnes différentes (BKEY et CKEY) dans A où les références BKEY références B.bkey et CKEY C.ckey et créer une contrainte qui assure que seul un est non NULL à tout moment.
  • Créer une sorte d'entité « B & C combiné » que B & C ont des clés étrangères et à faire la clé étrangère dans une référence la clé de cette entité combinée.

Si vous voulez une contrainte qui garantit exactement l'une des deux colonnes est NULL et on est NOT NULL pour une ligne

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

Autres conseils

Une contrainte de clé étrangère est de une table étrangère .
Cela signifie que vous auriez besoin d'utiliser deux déclarations ALTER TABLE dans cette situation à la configuration des clés étrangères pour référencer les deux tables. Il n'y a pas possibilité là pour spécifier un OU dans la relation - la valeur A.akey devrait exister dans les deux B.bkey et C.ckey en même temps . Par exemple, si B.bkey a une valeur NULL, mais C.ckey ne fonctionne pas - alors A.akey ne peut jamais avoir une valeur NULL. Les clés étrangères sont reportables dans Oracle, mais le comportement décrit est ce que vous rencontrerez si les deux clés étrangères sont activées en même temps - vous ne serez pas en mesure de permettre à une contrainte si toutes les valeurs ne satisfont pas la relation <. / p>

Vous devez passer en revue vos besoins pour la façon de simplifier la relation de sorte qu'il n'a pas besoin de deux tables pour faire ce travail.

On dirait que vous avez une certaine forme de relation sous-type / supertype passe. Un exemple typique est « personne » qui peut être un « client » ou un « fournisseur ».

Vous pourriez avoir, dans la table PERSONNE la clé unique de person_id plus un attribut de PERSON_TYPE ( 'CUST' ou 'SUPP'). Si vous créez la clé primaire sur person_id, PERSON_TYPE vous pouvez référencer que dans les tableaux de sous-type (Supplier / client).

Ensuite, vous ajoutez une contrainte unique sur le person_id pour faire en sorte que toute valeur de person_id doit être un client ou un fournisseur, mais pas les deux, et les contraintes de vérification sur les tables de sous-type de sorte que seul un type est représenté dans le tableau.

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');

Ce ne est pas assez, mais les types / sous-types sont plus d'un concept d'objet qu'un relationnel.

Ma solution inspirée par Justin:

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

Créer une vue matérialisée que les syndicats tables B & C, et le point de votre contrainte FK à la vue

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top