TableA Id INT PRIMARY KEY TableB Id INT PRIMARY KEY Parent INT NOT NULL FOREIGN KEY REFERENCES TableA.Id
我看到它的方式,我可以将以下列添加到TableA:
FavoriteChild INT NULL FOREIGN KEY REFERENCES TableB.Id
或表B中的以下列:
IsFavorite BIT NOT NULL
第一种方法的问题是它引入了一个可以为空的外键,据我所知,它不是标准化形式.第二种方法的问题是需要做更多的工作以确保最多只有一个孩子是最喜欢的.
我应该使用什么样的标准来确定使用哪种方法?或者,我还没有考虑其他方法吗?
我正在使用sql Server 2012.
解决方法
@Aaron更快地发现上面的命名约定相当麻烦并且可能导致错误.如果您的表中没有Id列,并且列(已连接的)在出现的许多表中具有相同的名称,那么通常会更好(并且会让您保持理智).所以,这是一个重命名:
Parent ParentID INT NOT NULL PRIMARY KEY Child ChildID INT NOT NULL PRIMARY KEY ParentID INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID) UNIQUE (ParentID,ChildID) FavoriteChild ParentID INT NOT NULL PRIMARY KEY ChildID INT NOT NULL FOREIGN KEY (ParentID,ChildID) REFERENCES Child (ParentID,ChildID)
在sql-Server(您正在使用)中,您还可以选择您提到的IsFavorite位列.每位父母最喜欢的孩子可以通过过滤的唯一索引来完成:
Parent ParentID INT NOT NULL PRIMARY KEY Child ChildID INT NOT NULL PRIMARY KEY ParentID INT NOT NULL FOREIGN KEY REFERENCES Parent (ParentID) IsFavorite BIT NOT NULL CREATE UNIQUE INDEX is_FavoriteChild ON Child (ParentID) WHERE IsFavorite = 1 ;
并且不建议使用选项1的主要原因是,外键引用中的循循环径模式存在一些问题,至少在sql-Server中不是这样.
阅读一篇相当古老的文章:SQL By Design: The Circular Reference
当从两个表中插入或删除行时,您将遇到“鸡与蛋”问题.我应该首先插入哪个表 – 不违反任何约束?
为了解决这个问题,您必须定义至少一个可为空的列. (好吧,从技术上讲你没必要,你可以将所有列都设置为NOT NULL,但只能在DBMS中,比如Postgres和Oracle,已经实现了可延迟的约束.请参阅@Erwin在类似问题中的答案:Complex foreign key constraint in SQLAlchemy如何实现这一点在Postgres完成).不过,这种设置感觉就像在冰上滑冰一样.
在SO(但是对于MysqL)In SQL,is it OK for two tables to refer to each other?检查一个几乎相同的问题,我的答案几乎相同. MysqL虽然没有部分索引,但唯一可行的选择是可以为空的FK和额外的表解决方案.