如何检查Oracle中的重叠约束?

时间:2017-04-27 12:37:12

标签: database oracle database-design relational-database data-modeling

假设B和C都是子类,A是超类。 B和C不能具有相同的id(不相交)

CREATE TABLE a(id integer primary key);
CREATE TABLE b(id integer references a(id));
CREATE TABLE c(id integer references a(id));
insert into a values('1');
insert into a values('2');
insert into b values('1');
insert into c values('2');

我可以使用触发器来阻止表B和C中出现相同的id吗?

3 个答案:

答案 0 :(得分:1)

  

“b和c不能有相同的ID”

因此,您希望强制实施互斥关系。在数据建模中,这称为弧。 Find out more

我们可以在没有触发器的表之间实现弧,方法是使用type列来区分子类型,如下所示:

create table a (
  id integer primary key
  , type varchar2(3) not null check (type in ( 'B', 'C'))
  , constraint a_uk unique (id, type)
);
create table b (
  id integer 
  , type varchar2(3) not null check (type = 'B')
  , constraint b_a_fk foreign key (id, type) references a (id, type)
);
create table b (
  id integer 
  , type varchar2(3) not null check (type = 'C')
  , constraint c_a_fk foreign key (id, type) references a (id, type)
);

超类型表除了主键外还有一个唯一的键;这为子类型表上的外键提供了参考点。我们仍然保留主键以确保id的唯一性。

子类型表具有type列的冗余实例,冗余,因为它包含固定值。但是这有必要引用复合唯一键的两列(而不是主键,更常见)。

这种密钥组合确保了如果超类型表具有记录id=1, type='B',则子类型表C中没有id=1的记录。

答案 1 :(得分:0)

您可以使用Oracle序列:

CREATE SEQUENCE multi_table_seq;

INSERT INTO A VALUE(1);
INSERT INTO A VALUE(2);
INSERT INTO B VALUE(multi_table_seq.NEXTVAL());  -- Will insert 1 in table B
INSERT INTO C VALUE(multi_table_seq.NEXTVAL());  -- Will insert 2 in table C
...

使用触发器:

-- Table B
CREATE TRIGGER TRG_BEFORE_INSERT_B  -- Trigger name
BEFORE INSERT                       -- When trigger is fire
ON A                                -- Table name
DECLARE
  v_id            NUMBER;
BEGIN
  v_id := multi_table_seq.NEXTVAL();
  BEGIN
     SELECT TRUE FROM C WHERE id = v_id;
     RAISE_APPLICATION_ERROR(-20010, v_id || ' already exists in table C');
  EXCEPTION WHEN NO_DATA_FOUND -- Do nothing if not found
  END;
END;

同样触发表C,检查表B中是否存在id

答案 2 :(得分:0)

设计明智这不好,但我们可以使用下面的代码片段来完成。您可以在表b

上创建类似的触发器
CREATE TABLE a(id integer primary key);
CREATE TABLE b(id integer references a(id));
CREATE TABLE c(id integer references a(id));

create or replace  trigger table_c_trigger before insert on c for each row
declare
counter number:=0;
begin
select count(*) into counter from b where id=:new.id;
if counter<>0 then
raise_application_error(-20001, 'values cant overlap between c and b');
end if;
end;

insert into a values('1');
insert into a values('2');
insert into b values('1');
insert into b values('2');
insert into c values('2');