【问题标题】:How do I ensure integrity between unrelated tables?如何确保不相关表之间的完整性?
【发布时间】:2017-04-14 14:25:25
【问题描述】:

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

我有这 3 个 DB 业务规则:

  • 每位官员必须注册一家且仅一家保险公司。每个保险公司可以招收一名或多名高级职员
  • 每个保险公司必须提供至少五种不同类型的保险类型。每种类型的保险最多可以由 4 家保险公司提供,或者根本不提供。
  • 每种保险类型都可以由一名或多名官员订阅。每个官员最多可以订阅同一家公司提供的五种不同的保险。

。 . .

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

各表的PK和FK属性如下:

INS_COY 表
coy_id - PK

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

INS_TYPE TABLE
type_id - PK

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

订阅
naf_notype_id -(复合 PK)
naf_no -(FK引用 offr.offr_id)
type_id (FK 引用 ins_type.type_id)

.
.
.

表已成功创建,示例数据已插入。

所以,问题是 - 在 SUBSCRIBE 表中,我如何确保附加到 OFFR_ID 的 TYPE_ID 是他注册的 COY 提供的 INS_TYPE 的完整性?

sample data tables

即...从表格中,“offr 4250”注册在“coy 1”中,而“coy 1”不提供“ins_type 13”,但是,因为没有限制检查这一点,“offr 1 " 订阅了 SUBSCRIBE TABLE 上的 "ins_type 13"。

【问题讨论】:

    标签: sql database oracle


    【解决方案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,但希望它能为您指明正确的方向。

    【讨论】:

    • 谢谢@reaanb。伟大的解决方案!我想我更喜欢使用触发器,因为我正在尽可能地避免冗余。但是,我从未使用过触发器。那么,如何使用触发器来实现呢?
    • 我添加了一个例子,希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-14
    • 2013-12-15
    • 2014-01-24
    • 2019-12-03
    • 2014-02-09
    • 1970-01-01
    相关资源
    最近更新 更多