Можно ли реализовать ссылочную целостность в таблице пересечений, чтобы ее родители имели одинаковое значение в столбце внешнего ключа? - PullRequest
0 голосов
/ 18 апреля 2020

Пример Oracle SQL Код:

create table t1 (
        t1a integer,
        t1b varchar2(30)
);
alter table t1 add constraint t1_pk primary key (t1a);
insert into t1 values (1, 'A');
insert into t1 values (2, 'B');

create table t11 (
        t11a integer,
        t1a  integer,
        t11b varchar2(30)
);
alter table t11 add constraint t11_pk primary key (t11a);
alter table t11 add constraint t11_t1_fk foreign key (t1a) references t1(t1a);
insert into t11 values (10, 1, 'A1');
insert into t11 values (11, 2, 'B1');

create table t12 (
        t12a integer,
        t1a  integer,
        t12b varchar2(30)
);
alter table t12 add constraint t12_pk primary key (t12a);
alter table t12 add constraint t12_t1_fk foreign key (t1a) references t1(t1a);
insert into t12 values (20, 1, 'A2');
insert into t12 values (21, 2, 'B2');

create table t1112 (
        t11a integer,
        t12a integer
);
alter table t1112 add constraint t1112_pk primary key (t11a, t12a);
alter table t1112 add constraint t1112_t11_fk foreign key (t11a) references t11(t11a);
alter table t1112 add constraint t1112_t12_fk foreign key (t12a) references t12(t12a);

create or replace trigger t1112_trg before insert or update on t1112 for each row
declare
        t11a_v  integer;
        t12a_v  integer;
begin
        select t11.t1a into t11a_v from t11 where t11.t11a = :new.t11a;
        select t12.t1a into t12a_v from t12 where t12.t12a = :new.t12a;
        if (t11a_v != t12a_v) then
                raise_application_error(-20000, 'Mismatch');
        end if;
end;
/

Таблица верхнего уровня: t1. t11 и t12 имеют ссылку внешнего ключа на t1. t1112 является таблицей пересечений между t1 и t2. Я хочу убедиться, что все строки, записанные в t1112, имеют комбинацию t11 и t12, так что они обе указывают на одну и ту же строку в t1.

Я попытался реализовать это с помощью триггера в примере. Есть ли способ сделать это через ограничения ссылочной целостности?

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

Самый простой способ - создать дополнительные уникальные ограничения для таблиц t11 и t12:

ALTER TABLE t11 ADD CONSTRAINT t11_un UNIQUE ( t11a, t1a );
ALTER TABLE t12 ADD CONSTRAINT t12_un UNIQUE ( t12a, t1a );

Добавить столбец t1a в таблицу T1112

ALTER TABLE t1112 ADD (t1a integer);

Удалить и воссоздать ограничения внешнего ключа для t1112:

ALTER TABLE T1112 DROP CONSTRAINT T1112_T11_FK;
ALTER TABLE T1112 ADD CONSTRAINT T1112_T11_FK FOREIGN KEY (t11a, t1a ) REFERENCES T11 (t11a, t1a);
ALTER TABLE T1112 DROP CONSTRAINT T1112_T12_FK;
ALTER TABLE T1112 ADD CONSTRAINT T1112_T12_FK FOREIGN KEY (t12a, t1a ) REFERENCES T12 (t12a, t1a);

Так что теперь они используют два уникальных ограничения вместо первичных ключей. Общий столбец t1a в таблице соединений гарантирует, что ключи от t11 и t12 соединятся обратно с t1.

0 голосов
/ 18 апреля 2020

Используйте материализованное представление:

CREATE MATERIALIZED VIEW t11_t12_mv
   BUILD IMMEDIATE
   AS SELECT t11a, t12a
      FROM   t11 INNER JOIN t12 ON t11.t1a = t12.t1a;

ALTER TABLE t11_t12_mv ADD CONSTRAINT t11a_t12a__pk PRIMARY KEY ( t11a, t12a );

create table t1112 (
  t11a integer,
  t12a integer,
  CONSTRAINT t1112_pk PRIMARY KEY (t11a, t12a),
  CONSTRAINT t1112_fk FOREIGN KEY (t11a, t12a) REFERENCES t11_t12_mv ( t11a, t12a )
);

Тогда:

INSERT INTO t1112 VALUES ( 10, 20 );
INSERT INTO t1112 VALUES ( 11, 21 );

Работает. Однако:

INSERT INTO t1112 VALUES ( 10, 21 );

Возникает исключение:

ORA-02291: integrity constraint (USER_4_F249D.T1112_FK) violated - parent key not found 

sqlfiddle здесь

...