【问题标题】:How to enforce uniques across multiple tables如何在多个表中强制执行唯一性
【发布时间】:2011-01-18 12:52:08
【问题描述】:

我在 MySQL 服务器中有以下表格:

Companies:
- UID (unique)
- NAME
- other relevant data

Offices:
- UID (unique)
- CompanyID
- ExternalID
- other data

Employees:
- UID (unique)
- OfficeID
- ExternalID
- other data

在每一个中,UID 都是唯一的标识符,由数据库创建。

有外键来保证 UID 上 Employee -> Office -> Company 之间的链接。

办公室和员工中的 ExternalID 字段是公司(实际上是我的客户)提供给我的申请的 ID。客户不知道(也不关心)我自己的 ID,我的应用程序从他们那里收到的所有数据都是仅根据他们的 ID(即我的表中的 ExternalID)来识别的。

即来自客户的伪语言请求类似于“我是 X 公司,更新我的员工 Y 的数据”。

我需要对 CompanyID 和Employees.ExternalID 的组合强制唯一性,因此在我的数据库中,同一公司的员工不会有重复的ExternalID。

我在考虑 3 种可能的解决方案:

  1. 更改员工的架构以包含 CompanyID,并在两个字段上创建唯一约束。

  2. 强制执行触发器,该触发器在员工中更新/插入时会验证唯一性。

  3. 强制检查应用程序级别(即我的接收服务)。

我的替代 dbadmin-in-me 说 (3) 是最糟糕的解决方案,因为它不能保护数据库的不一致以防应用程序错误或其他问题,而且很可能是最慢的解决方案。

触发器解决方案可能是我想要的,但它可能会变得复杂,特别是如果需要在单个语句中执行多个插入/更新,并且我不确定与 (1) 相比的性能。

而且 (1) 看起来是最快和最简单的方法,但有点违背我对关系模型的理解。

SO DB 专家对每种方法的优缺点有何看法,特别是如果有可能添加额外的间接级别 - 即公司 -> 办公室 -> 部门 -> 员工,并且需要相同的唯一性保留(公司/员工)。

【问题讨论】:

    标签: sql mysql database database-design data-modeling


    【解决方案1】:

    您公司提供的每个表都应将CompanyID 包含在公司提供的ID 上的“唯一键”中。

    公司提供的参照完整性应使用公司提供的 ID:

    CREATE TABLE company (
            uid INT NOT NULL PRIMARY KEY,
            name TEXT
            );
    
    CREATE TABLE office (
            uid INT NOT NULL PRIMARY KEY,
            companyID INT NOT NULL,
            externalID INT NOT NULL,
            UNIQIE KEY (companyID, externalID),
            FOREIGN KEY (companyID) REFERENCES company (uid)
            );
    
    CREATE TABLE employee (
            uid INT NOT NULL PRIMARY KEY,
            companyID INT NOT NULL,
            officeID INT NOT NULL,
            externalID INT NOT NULL,
            UNIQIE KEY (companyID, externalID),
            FOREIGN KEY (companyID) REFERENCES company(uid)
            FOREIGN KEY (companyID, officeID) REFERENCES office (companyID, externalID)
            );
    

    等等

    【讨论】:

    • 感谢您的回复 - 所以选择一。
    【解决方案2】:

    您是对的 - #1 是最佳选择。
    诚然,我乍一看会质疑(因为走捷径),但了解业务规则以确保员工仅与一家公司相关 - 这是有道理的。

    此外,我还有一个外键,将员工表中的 companyid 与 office 表中的 companyid 关联起来。否则,您允许员工与没有办公室的公司相关联。除非这是可以接受的......

    如果关系不能在数据模型中展示,触发器是最后的手段,并且从应用程序中为逻辑提供服务意味着逻辑是集中的 - 没有机会发生不良数据,除非有人放弃约束(这意味着您有更大的问题)。

    【讨论】:

    • @OMG:是的,外键是外键。为简单起见,我没有在 Q 中添加它们。无论如何,感谢您发现这一点。我将编辑 Q。
    【解决方案3】:

    将 auto_increment_increment 设置为您拥有的表数。 SET auto_increment_increment = 3; (你可能想在你的 my.cnf 中设置它)

    然后手动将每个表的起始auto_increment值设置为不同的值 第一个表到 1,第二个表到 2,第三个表到 3

    表 1 将具有 1、4、7、10、13 等值

    表 2 将具有 2、5、8、11、14 等值

    表 3 将具有 3、6、9、12、15 等值

    当然,这只是一个选项,我个人只是将其设为组合值。可以像 TableID、AutoincrementID 一样简单,其中 TableID 在所有行中都是常量。

    【讨论】:

    • 当您添加第 4 个表时,这将非常失败。
    • 有趣的想法。那么,我究竟如何执行 Company+Employee.ExternalID 组合的唯一性呢?
    • 回想起来,我的想法很愚蠢,尽管创建独特想法的一种有趣方法是通过票务表。 code.flickr.com/blog/2010/02/08/…
    • 仍然没有回答我的问题,但是这篇文章很有趣。感谢分享。
    猜你喜欢
    • 2021-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多