(我有点大脑屁,我不记得这个问题类的名字了,因为我之前已经看过这个问题的解决方案了,所以请把它标记为另一个的重复如果你以前在这里找到更好的答案,请提出问题。)
想象一下,我们有一个汽车和CarOwners数据库。每个CarOwner都有很多汽车(一对多),但每个CarOwner都有一辆最喜欢的汽车。
这是一个初始架构:
CREATE TABLE Owners (
OwnerId bigint IDENTITY(1,1) PRIMARY KEY,
Name nvarchar(100)
)
CREATE TABLE Cars (
CarId bigint IDENTITY(1,1) PRIMARY KEY,
Vin varchar(17),
OwnerId bigint,
FOREIGN KEY (OwnerId) REFERENCES Owners(OwnerId)
)
对于拥有最喜欢的汽车的所有者,需要使用带有外键约束的新列Owners
扩展FaveCarId bigint
表到Cars
表,但添加了所有者和汽车之间的不一致耦合(例如,如果我们将Houses
或Computers
添加到数据库,当我们获得有关所有者的信息时,我们不关心他们的FaveCar
是什么。这也增加了鸡和蛋的问题,FaveCar
列必须NULL
能够创建Owner
行,添加新的Car
行,然后添加新的CarID
返回FaveCar
列。
...所以另一种解决方案是扩展Cars
列以添加布尔IsFavourite
列,但这有一个问题,即没有任何东西阻止某人提供两个Car
s(属于同一Owner
)集合IsFavourite
列值。唯一约束(在OwnerId+IsFavourite
之间也无济于事,因为如果所有者拥有3辆或更多车辆,其中2辆将拥有IsFavourite=0
。
答案 0 :(得分:1)
关联表解决方案
CREATE TABLE OwnersFavoriteCar (
OwnerId bigint PRIMARY KEY,
CarId bigint,
FOREIGN KEY (OwnerId) REFERENCES Owners(OwnerId),
FOREIGN KEY (CarId) REFERENCES Cars(CarId)
);
您可以创建通常用于M:N
关系的关联表,但将主键设置为OwnerId
。这可以防止车主拥有一辆以上的车。
如果您认为自己可以添加House
或Computer
,并且除了Car
之外,所有者也会收藏一个,您可以将其重命名为{ {1}}并添加两列:
OwnersFavoriteStuff
数据库继承解决方案
或者,您可以继续进行数据库继承:
HouseId bigint -- with FK constraint
ComputerId bigint -- with FK constraint
使用此数据库无效模式,CREATE TABLE Things (
ThingId bigint PRIMARY KEY
ThingType nvarchar(10) CHECK (ThingType in ('car', 'house')) -- type discriminator
);
CREATE TABLE Cars (
ThingId bigInt PRIMARY KEY,
Vin nvarchar(17),
OwnerId bigint,
FOREIGN KEY (OwnerId) REFERENCES Owners(OwnerId),
FOREIGN KEY (ThingId) REFERENCES Things(ThingId)
);
CREATE TABLE Houses (
ThingId bigInt PRIMARY KEY,
Color nvarchar(17),
Rooms bigint,
OwnerId bigint,
FOREIGN KEY (OwnerId) REFERENCES Owners(OwnerId),
FOREIGN KEY (ThingId) REFERENCES Things(ThingId)
);
CREATE TABLE OwnersFavoriteThing (
OwnerId bigint ,
ThingId bigint,
Type nvarchar(10) CHECK (Type in ('Car', 'House')), -- Used to discriminate amoung different Things
PRIMARY KEY (OwnerId, ThingId), -- Makes sure that owner cannot have more than one favorite thing of each type
FOREIGN KEY (OwnerId) REFERENCES Owners(OwnerId),
FOREIGN KEY (ThingId) REFERENCES Things(ThingId)
);
是最高级别,Things
和Cars
都扩展为Houses
。
您通常会在Things
和BEFORE INSERT
上使用Cars
触发器,该触发器会先将行插入Houses
,获取新的ThingId,并将其插入{ {1}}或Things
。
现在,无论您在数据库中创建了多少个新表,您的FavoriteThing表仍保持第三范式。 Cars
列用于区分不同类型的Houses
。
答案 1 :(得分:1)
尝试以下数据模型:
IsFavorite是OwnedCar的一个属性,由两者 Person和Car识别,而不仅仅由Person或Car识别。 因此需要复合键 您可以将IsFavorite实现为OwnedCar列,也可以创建一个新实体FavoriteCar来增加完整性。
要约束OwnedCar和FavoriteCar,您需要创建唯一索引(备用密钥)。
没有复合钥匙的问题是,您可以插入所有者不拥有汽车的喜爱汽车。
CREATE TABLE OwnersFavoriteCar (
OwnerId bigint PRIMARY KEY,
CarId bigint,
FOREIGN KEY (OwnerId) REFERENCES Owners(OwnerId),
FOREIGN KEY (CarId) REFERENCES Cars(CarId)
);