以“抓”的n:m
关系:
Person
------
PersonId
PRIMARY KEY (PersonId)
PersonGroup
-----------
GroupId
PRIMARY KEY (GroupId)
Belongs
-------
GroupId
PersonId
Ordering
PRIMARY KEY (GroupId, PersonId)
FOREIGN KEY (GroupId)
REFERENCES PersonGroup (GroupId)
FOREIGN KEY (PersonId)
REFERENCES Person (PersonId) --- all normal up to here
UNIQUE KEY (GroupId, Ordering) --- the "catch"
CONSTRAINT Ordering_chk --- ensuring only up to 8 persons
CHECK Ordering IN (1,2,3,4,5,6,7,8) --- per group
你应该确保在CHECK
约束是在你使用SQL引擎可用的(MySQL的例子就是诱骗用户相信它有这样但它只是忽略它们SQL-Server不会返回错误,但如果您尝试插入一个,则在检查列中愉快地添加NULL
)。
这种方法存在限制。 Ordering
字段必须是NOT NULL
,因为如果它是NULL
,可以插入超过8行(其中包含NULL)(SQL-Server除外,只允许最多9行,其中8个包含值,另一个包含NULL)。)
为了确保最高的8行和NULL值在Ordering
的,你可以让像MSDN site, CHECK Constraints描述的一个较为复杂的约束(如果您的RDBMS有这样的功能),但我不上的表现都肯定这样的野兽:
CREATE FUNCTION CheckMax8PersonPerGroup()
RETURNS int
AS
BEGIN
DECLARE @retval int
SELECT @retval = CASE WHEN EXISTS
(SELECT *
FROM Belongs
GROUP BY GroupId
HAVING COUNT(*) > 8
)
THEN 0
ELSE 1
END
RETURN @retval
END;
GO
ALTER TABLE Belongs
ADD CONSTRAINT Ordering_chk
CHECK (CheckMax8PersonPerGroup() = 1);
GO
约束可替代地创建为FOREIGN KEY
到参考表8点的行。 (如果你使用MySQL,这是为具有CHECK
同等的唯一途径。)
的变化是使用了(GroupId, Ordering)
作为主键,而不是对(GroupId, PersonId)
组合的任何约束。这将允许Person
在Group
(但仍然高达8)中具有多个职位。