Database 数据库约束

Database 数据库约束,database,database-design,uml,relational-database,database-schema,Database,Database Design,Uml,Relational Database,Database Schema,我有一个包含三个表的数据库:团队,球员,合同 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,

我有一个包含三个表的数据库:
团队
球员
合同

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)

因此,我的球员有一份从2000年1月1日到2005年1月1日的合同,还有一份从2001年1月1日到2003年1月1日的合同。这是不可能的。

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

您将有两个选择:

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

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

如果在合同表中使playerid唯一,并添加另一个表以保存合同历史记录。一名球员只能有一次接触,但可以有多次接触


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

一名球员的两份不同合同不会重叠,如果且仅当一份合同在另一份合同完成后开始。因此,当且仅当不重叠时(一个在另一个完成后开始)。您需要的约束是,压缩对的任何行都不满足它们重叠的条件:

    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)
但它们不是,所以您必须在触发器或存储过程中测试这个选择。(如另一个答案中所解释的)DBMS不支持任意约束检查

您可以通过将过期的合同保存在与活动合同不同的表中来减少计算量。(它们不会和新的重叠。)但我刚刚用了你给的桌子

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)
CHECK (SELECT CASE
        WHEN EXISTS (SELECT 1 FROM (...))
        THEN 1
        ELSE 0 END)