如何确保不相关表之间的完整性?

时间:2017-04-14 14:25:25

标签: sql database oracle

我刚刚开始学习数据库设计,我正在使用Oracle 11G和SQL Developer。

我有一个DB的这3个业务规则:

  • 每位官员必须注册一个且仅有一个保险公司。每个保险公司可以注册一个或多个官员
  • 每个保险公司必须提供至少五种不同类型的保险类型。每种保险类型最多可由4家保险公司提供或根本不提供
  • 每个保险类型可由一个或多个OFFICERS订阅。每个官员可以订购由同一家公司提供的最多五种不同的保险范围。

。 。

到目前为止,非常好,我想出了五个表( INS_COY,OFFR,INS_TYPE,PROVIDE和SUBSCRIBE )。 PROVIDE和SUBSCRIBE作为复合表出现,因为INS_COY和INS_TYPE之间的关系,以及OFFR和INS_TYPE都是M:M关系。

每个表的PK和FK属性如下:

INS_COY TABLE
coy_id - PK

OFFR TABLE
offr_id - PK
coy_id - (FK引用INS_COY.coy_id))

INS_TYPE TABLE
type_id - PK

提供
coy_id type_id - (复合PK)
coy_id - (FK引用COY.coy_id)
type_id - (FK引用ins_type.type_id)

SUBSCRIBE
naf_no type_id - (复合PK)
naf_no - (FK引用offr.offr_id)
type_id (FK引用ins_type.type_id)



表已成功创建,并插入了样本数据。

所以,问题是 - 在SUBSCRIBE TABLE上,我如何确保TYPE_ID附加到OFFR_ID的完整性是由他所引入的COY提供的INS_TYPE?

sample data tables

即...来自表格,“offr 4250”在“coy 1”中注册,“coy 1”不提供“ins_type 13”,但是,因为没有约束来检查这个,“offr 1 “在SUBSCRIBE TABLE上订阅了”ins_type 13“。

1 个答案:

答案 0 :(得分:1)

您可以使用受控冗余和复合FK约束来实现:

CREATE TABLE offr (
    offr_id INT NOT NULL,
    coy_id INT NOT NULL,
    PRIMARY KEY (offr_id),
    FOREIGN KEY (coy_id) REFERENCES ins_coy (coy_id),
    UNIQUE KEY (offr_id, coy_id)
);

我添加了一个复合唯一键(offr_id,coy_id)来支持subscribe表上的复合FK约束。

CREATE TABLE provide (
    coy_id INT NOT NULL,
    type_id INT NOT NULL,
    PRIMARY KEY (coy_id, type_id),
    FOREIGN KEY (coy_id) REFERENCES ins_coy (coy_id)
);

此处的复合主键非常适合subscribe表上的复合FK约束。

CREATE TABLE subscribe (
    naf_no INT NOT NULL,
    coy_id INT NOT NULL,
    type_id INT NOT NULL,
    PRIMARY KEY (naf_no, type_id),
    FOREIGN KEY (naf_no, coy_id) REFERENCES offr (offr_id, coy_id),
    FOREIGN KEY (coy_id, type_id) REFERENCES provide (coy_id, type_id)
);

重叠的复合FK约束将确保官员只能订阅他/她注册的公司提供的保险。coy_id在逻辑上是多余的,但是要求完整性,并且不存在更新异常的风险。 FK约束。

或者,您可以使用触发器通过内部联接检查值是否相关:

CREATE TRIGGER check_subscribe BEFORE INSERT OR UPDATE ON subscribe
FOR EACH ROW
WHEN NOT EXISTS (
    SELECT 1
    FROM offr
    INNER JOIN provide ON offr.coy_id = provide.coy_id
    WHERE offr.offr_id = new.naf_no AND provide.type_id = new.type_id
)
RAISE_APPLICATION_ERROR (num => -20000, msg => 'Officers can only subscribe to types provided by their company');

免责声明:我无法在SqlFiddle上测试这个并且没有安装Oracle,但希望它能指向正确的方向。