Pregunta

Tengo una tabla (A) cuya clave primaria es o bien una clave externa a la mesa (B) o la tabla (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)
);

Lo que quiero es algo como:

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

¿Es esto posible?

¿Fue útil?

Solución

No, ese tipo de cosas no es posible en Oracle.

Sus opciones son generalmente

  • Crea dos columnas diferentes (tecla B y CKEY) en un donde las referencias tecla B B.bkey y CKEY referencias C.ckey y crear una restricción que asegura que sólo un no es nulo en cualquier punto en el tiempo.
  • Crea una especie de "B & C combinado" entidad que B y C tienen las claves externas y hacer a la clave externa de una referencia a la clave de esta entidad combinación.

Si desea una restricción que asegura que precisamente una de las dos columnas es nulo y uno no es NULL para cualquier fila

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

Otros consejos

Una restricción de clave externa es a una tabla externa .
Eso significa que había necesidad de utilizar dos sentencias ALTER TABLE en esta situación para configurar las claves externas para hacer referencia a las dos tablas. No hay oportunidad en la que hay que especificar un OR en la relación - el valor en A.akey tendría que existir en tanto B.bkey y C.ckey al mismo tiempo . Por ejemplo, si B.bkey tiene un valor de NULL, pero no lo hace C.ckey - A.akey entonces nunca puede tener un valor de NULL. Las claves externas son diferible en Oracle, pero el comportamiento descrito es lo que se encontrará si las dos claves externas se activan al mismo tiempo - que no será capaz de activar una restricción si todos los valores no satisfacen la relación <. / p>

Es necesario revisar sus necesidades de manera de simplificar la relación por lo que no necesita dos tablas para hacer este trabajo.

Parece que tienes algún tipo de subtipo / supertipo relación pasando. Un ejemplo típico es 'persona' que puede ser o bien un 'cliente' o un 'PROVEEDOR'.

Es posible que tenga, en la tabla PERSONA la clave única de person_id además un atributo de PERSON_TYPE ( 'MEM' o 'SUPP'). Si se crea la clave principal en person_id, PERSON_TYPE puede hacer referencia a que en las mesas de subtipo (proveedor / cliente).

A continuación, añadir una restricción única en la person_id para asegurar que cualquier valor de person_id debe ser un cliente o proveedor, pero no ambos, y restricciones de comprobación en las mesas del subtipo de manera que un solo tipo está representado en la tabla.

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

No es bonita, pero los tipos / subtipos son más de un concepto de objeto que uno relacional.

Mi solución inspirada en 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

Crea una vista materializada que las tablas sindicatos B y C, y apuntar su restricción FK a la vista

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top