我有一个包含三个表的数据库:TEAM
,PLAYER
,CONTRACT
。
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。这是不可能的。
答案 0 :(得分:1)
这不能通过声明性约束直接强制执行。不幸的是,目前的DBMS不提供“独特范围”约束(至少据我所知)。
您有两种选择:
注意:后者可以更精细,例如天,但这将在数据库中产生更多行并导致闰年等问题 - 您需要为您的特定情况找到合适的平衡。
答案 1 :(得分: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。 (如另一个答案所述。)DBMSes不支持任意约束检查。
您可以通过将过期合同保留在与活动合同不同的表中来减少计算。 (它们不会与新的重叠。)但我刚刚使用了你提供的表格。
答案 2 :(得分:0)
如果在合约表中,您使playerid成为唯一,并添加另一个表来保存合同历史记录。然后玩家只能拥有一个联系人但可能拥有多个联系人。
在业务层中,您需要确定要插入的合同是否应覆盖当前合同。如果是,请归档并从合同表中删除当前合同并插入新合同。