Domanda

Ho una tabella (A) la cui chiave primaria è o una chiave esterna tabella (B) o una tabella (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)
);

Quello che voglio è qualcosa di simile:

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

È possibile?

È stato utile?

Soluzione

No, questo genere di cose non è possibile in Oracle.

Le opzioni sono generalmente

  • Creare due diverse colonne (tasto B e CKEY) in cui A riferimenti tasto B B.bkey e CKEY riferimenti C.ckey e creare un vincolo che assicura che solo uno è nullo in qualsiasi punto nel tempo.
  • creare una sorta di "combinata B & C" entità che B & C hanno le chiavi stranieri e rendere la chiave esterna in un riferimento chiave di questa entità combinazione.

Se si desidera un vincolo che garantisce che esattamente una delle due colonne è NULL e uno non è nullo per qualsiasi riga

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

Altri suggerimenti

Un vincolo di chiave esterna è quello di una tabella esterna .
Ciò significa che avresti bisogno di utilizzare due prospetti ALTER TABLE in questa situazione per l'installazione chiavi esterne per fare riferimento le due tabelle. Non c'è alcuna possibilità in là di specificare un OR nella relazione - il valore in A.akey avrebbe dovuto esistere sia B.bkey e C.ckey al tempo stesso . Ad esempio, se B.bkey ha un valore NULL, ma non lo fa C.ckey - A.akey quindi non può mai avere un valore NULL. Le chiavi esterne sono differibile in Oracle, ma il comportamento descritto è ciò che si incontrano se entrambe le chiavi esterne sono abilitate allo stesso tempo - non sarà in grado di abilitare un vincolo se tutti i valori non soddisfano la relazione <. / p>

È necessario rivedere le vostre esigenze per il modo di semplificare il rapporto in modo che non ha bisogno di due tavoli per fare questo lavoro.

sembra che tu abbia una qualche forma di sottotipo / supertipo rapporto in corso. Un esempio tipico è 'persona' che può essere sia un 'cliente' o un 'FORNITORE'.

Si potrebbe avere, nella tabella PERSONA la chiave univoca di person_id più un attributo di PERSON_TYPE ( 'CUST' o 'SUPP'). Se si crea la chiave primaria sul person_id, PERSON_TYPE è possibile fare riferimento che nelle tabelle sottotipo (fornitore / cliente).

Poi si aggiunge un vincolo unico sul person_id per garantire che qualsiasi valore person_id deve essere un cliente o un fornitore, ma non entrambi, e vincoli di controllo sulle tavole sottotipo in modo che un solo tipo è rappresentato nella tabella.

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

La sua non è bella, ma tipi / sottotipi sono più di un concetto oggetto di uno relazionale.

La mia soluzione ispirata a 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

Creare una vista materializzata che i sindacati tabelle B e C, e puntare il vincolo FK alla vista

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top