假设我有以下表格
Companies
--CompanyID
--CompanyName
和
Locations
--LocationID
--CompanyID
--LocationName
每家公司至少有一个地点。我想跟踪每家公司的primary
位置(是的,每家公司都只有一个主要位置)。设置它的最佳方法是什么?在primaryLocationID
表中添加Companies
?
答案 0 :(得分:2)
在Companies表中添加primaryLocationID?
是的,但是这会创建一个循环引用,可能会阻止您插入新数据:
解决这个鸡蛋问题的一种方法是简单地让Company.PrimaryLocationID
为空,这样你就可以暂时禁用其中一个圆形FK。遗憾的是,数据库只会强制执行“1:0..1”,而不是严格的“1:1”关系(因此您必须在应用程序代码中强制执行)。
但是,如果您的DBMS支持延迟约束(例如Oracle或PostgreSQL),您可以简单地推迟其中一个FK以在事务仍在进行时中断循环。在交易结束时,两个FK都必须到位,从而产生真正的“1:1”关系。
另一种解决方案是在Locations
表中为主要位置设置一个标志,并在非主要位置设置NULL(注意U1
,表示UNIQUE约束,确保公司不能有多个主要位置):
CREATE TABLE Location (
LocationID INT PRIMARY KEY,
CompanyID INT NOT NULL, -- References Company table, not shown here.
LocationName VARCHAR(50) NOT NULL, -- Possibly UNIQUE?
IsPrimary INT CHECK (IsPrimary IS NULL OR IsPrimary = 1), -- Use a BIT or BOOLEAN if supported by your DBMS.
CONSTRAINT Locations_U1 UNIQUE (CompanyID, IsPrimary)
);
不幸的是,这有一些问题:
BaBL86's solution型号M:N,而您的要求似乎是1:N。尽管如此,通过在{LocationID}
(和{CompanyID, TypeOfLocation}
上放置一个密钥来确保同一公司不能有多个相同类型的位置),可以将该模型“强制”为1:N,但是可能过度设计了一个简单的“主要”要求。
答案 1 :(得分:1)
我认为您自己的解决方案是最好的 - 这可以确保每家公司只能拥有一个主要位置。通过将其设为NOT NULL
列,您甚至可以强制执行每个公司都应该拥有主要位置。
使用BaBL86's solution,您没有这些限制:公司可以拥有0 - 无限制的“主要位置”,这显然是不可能的。
请注意,如果您使用外键约束并将primaryLocationID定义为NOT NULL
列,则会遇到问题,因为您基本上有一个循环(位置指向公司,公司指向位置)。您无法创建新公司(因为它需要主要位置),也无法创建新位置(因为它需要公司)。
答案 2 :(得分:-1)
我使用数据透视表:
CompanyLocations
--CompanyID
--LocationID
--TypeOfLocation (primary, office, warehouse etc.)
在这种情况下,您可以根据需要选择所有位置,而不是使用类型。如果您创建PrimaryLocationID - 您需要一个表的两个连接和更复杂的逻辑。这比这还糟糕。