是否可以在交集 table 上实现参照完整性,以便它的父项在外键列上具有相同的值?
Is it possible to implement referential integrity on an intersection table so that it's parents have the same value on a foreign key column?
示例 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;
/
顶级table:t1。
t11 和 t12 有一个指向 t1 的外键引用。
t1112 是 t1 和 t2 之间的交集 table。
我想确保写入 t1112 的任何行都具有 t11 和 t12 的组合,以便它们都指向 t1 中的同一行。
我尝试在示例中使用触发器来实现它。有没有办法通过参照完整性约束来做到这一点?
使用物化视图:
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 here
最简单的方法是在 tables t11 和 t12 上创建额外的唯一约束:
ALTER TABLE t11 ADD CONSTRAINT t11_un UNIQUE ( t11a, t1a );
ALTER TABLE t12 ADD CONSTRAINT t12_un UNIQUE ( t12a, t1a );
将列 t1a
添加到 table 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);
这样他们现在使用两个唯一约束而不是主键。连接 table 中的共享列 t1a
将确保来自 t11
和 t12
的键连接回 t1
。
示例 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;
/
顶级table:t1。 t11 和 t12 有一个指向 t1 的外键引用。 t1112 是 t1 和 t2 之间的交集 table。 我想确保写入 t1112 的任何行都具有 t11 和 t12 的组合,以便它们都指向 t1 中的同一行。
我尝试在示例中使用触发器来实现它。有没有办法通过参照完整性约束来做到这一点?
使用物化视图:
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 here
最简单的方法是在 tables t11 和 t12 上创建额外的唯一约束:
ALTER TABLE t11 ADD CONSTRAINT t11_un UNIQUE ( t11a, t1a );
ALTER TABLE t12 ADD CONSTRAINT t12_un UNIQUE ( t12a, t1a );
将列 t1a
添加到 table 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);
这样他们现在使用两个唯一约束而不是主键。连接 table 中的共享列 t1a
将确保来自 t11
和 t12
的键连接回 t1
。