【问题标题】:Database Constraints数据库约束
【发布时间】:2014-12-13 23:41:08
【问题描述】:

我有一个包含三个表的数据库:TEAMPLAYERCONTRACT

TEAM(teamID, name)
PLAYER(playerID, name)
CONTRACT(contractID, playerID, teamID, dateOfSigning, expirationDate)

在这个数据库中,我想要一个玩家不能同时拥有多个合同的约束。 我提到我希望过期的合同仍保留在我的数据库中。

例如:

CONTRACT(1,1,1, 01/01/2000, 01/01/2005)
CONTRACT(1,1,1, 01/01/2001, 01/01/2003)

所以,我的球员有一份从 01/01/2000 到 01/01/2005 的合同,还有一份从 01/01/2001 到 01/01/2003 的合同。 strong> 这是不可能的。

【问题讨论】:

    标签: database database-design uml relational-database database-schema


    【解决方案1】:

    当且仅当一个球员在另一个合同结束后开始时,球员的两个不同合同才不会重叠。因此,当且仅当 NOT(一个在另一个完成后开始)时,它们才会重叠。您想要的约束是没有任何 contractID 对的行满足它们重叠的条件:

        CONTRACT(c1.contractID, playerID, c1.teamID, c1.dateOfSigning, c1.expirationDate)
    AND CONTRACT(c2.contractID, playerID, c2.teamID, c2.dateOfSigning, c2.expirationDate)
    AND c1.contractID <> c2.contractID
    AND NOT(c1.dateOfSigning > c2.expirationDate
        OR c2.dateOfSigning > c1.expirationDate)
    

    这意味着以下行集是空的:

    SELECT c1.contractID, c2.contractID
    FROM CONTRACT c1
    JOIN CONTRACT c2
    ON c1.playerID = c2.playerID
    AND c1.contractID <> c2.contractID
    WHERE NOT(c1.dateOfSigning > c2.expirationDate
        OR c2.dateOfSigning > c1.expirationDate)
    

    如果 DBMS 支持 CHECK 中的 SELECT,那么您可以有一个 CONTRACT 约束:

    CHECK (SELECT CASE
            WHEN EXISTS (SELECT 1 FROM (...))
            THEN 1
            ELSE 0 END)
    

    但它们没有,因此您必须在触发器或存储过程中测试此 SELECT。 (正如另一个答案中所解释的那样。)DBMS 不能很好地支持任意约束检查。

    您可以通过将过期合同保存在与活动合同不同的表中来减少计算量。 (它们不会与新的重叠。)但是我刚刚使用了您提供的表格。

    【讨论】:

      【解决方案2】:

      这不能通过声明性约束直接强制执行。不幸的是,当前的 DBMS 不提供“唯一范围”约束(至少据我所知)。

      你有两个选择:

      • 通过您的业务逻辑(通常是触发器或存储过程)强制执行此操作。但请注意并发(您可能需要使用锁定来避免并发事务之间的竞争条件与相关日期有关)。
      • 或者降低时间粒度。例如,如果您将年份划分为月份,并声明给定合同“占用”了哪些月份(通过为每个月设置单独的行),那么您可以轻松(并且以声明方式!)强制执行相同的不能存在重复月。

      注意:后者可以更细化,例如天,但这会在数据库中产生更多行并导致闰年等问题 - 您需要为您的特定情况找到合适的平衡。

      【讨论】:

        【解决方案3】:

        如果您在合约表中设置了唯一的 playerid 并添加另一个表以保留合约历史记录。一个玩家只能有一个联系人,但可以有很多。

        在业务层中,您需要决定插入的合同是否应该覆盖当前合同。如果是这样,存档并从合同表中删除当前合同并插入新合同。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-10
          • 1970-01-01
          • 2021-09-04
          相关资源
          最近更新 更多