我正在开发一个网络应用程序,我必须设计它的数据库。有一部分对我来说并不是那么简单,所以经过一些思考和研究后,我得到了多个想法。似乎仍然不合适,所以我不确定实施哪一个以及为什么。
简化问题如下: 我有一张桌子老师。根据与其领域和主题的关系,有两种类型的教师:
我最初的想法是拥有两个可以为空的外键,一个用于表Field,另一个用于表Category。但在这种情况下,我怎样才能确保一个是空的,而另一个不是?
另一个想法是创建一个层次结构,有两种类型的教师表派生自表Teacher(is-a relation),但我找不到任何有用的教程。
我正在使用带有SQLite数据库的Django开发应用程序
答案 0 :(得分:1)
好的,你的评论让它更加清晰:
如果教师只属于一个类别,您应该直接将其保存在教师的表格中:
其次,每个教师属于"一个或零"领域。如果这是肯定的,你应该使用可空的FieldID列。这已设置或保持为空。
Category (CategoryID, Name, ...)
Field (FieldID,Name,...)
Teacher (TeacherID,FieldID [NULL FK],CategoryID [NOT NULL FK], FirstName, Lastname, ...)
备注:这与我最后一个答案的映射表几乎相同。唯一的区别是,您对"完全一个"有严格的限制。或者"完全没有或一个" ...根据我的经验,我仍然更喜欢开放的方法。使用包括TeacherID列的唯一索引可以轻松实施规则。迟早你可能不得不重新构建这个...
当你继续时,一个类别与"零或更多"相关。领域。有两种方法:
将CategoryID列添加到Field-table(NOT NULL FK)。这样,您可以使用不同的CategoryID(组合唯一索引!)多次定义字段。您可以通过向Field-table询问具有给定CategoryID的所有字段来获取类别的字段列表。
在我眼里更好的是一个映射表CategoryField。如果您强制执行唯一的FieldID,您将确保无法将字段映射两次。并在CategoryID和FieldID的组合上添加唯一索引...
SELECT可能是这样的(SQL Server语法,未经测试):
SELECT Teacher.TeacherID
,Teacher.FieldID --might be NULL
,Teacher.CategoryID --never NULL
,Teacher.[... Other columns ...]
,Field.Name --might be NULL
--The following columns you pick from the right source,
--depending on the return value of the LEFT JOIN to Field and the related "catField"
--the directly joined "Category" (which is never NULL) is the "default"
,ISNULL(catField.CategoryID,Category.CategoryID) AS ResolvedCategoryID
,ISNULL(catField.Name,Category.Name) AS ResolvedCategoryName
,[... Other columns ...]
FROM Teacher
INNER JOIN Category ON Teacher.CategoryID=Category.CategoryID --never NULL
LEFT JOIN Field ON Teacher.FieldID=Field.FieldID --might be NULL
LEFT JOIN Category AS catField ON Field.CategoryID=catField.CategoryID
这是编辑前的答案: 即使这个概念对我来说不是很清楚,我也会尽力帮助你
Teacher-Table: TeacherID, person's data (name, address...), ...
Category-Table: CategoryID, category title, ...
Field-Tabls: FieldID, field title, ...
你说,在所有情况下,这些字段都绑定到一个类别。如果在所有情况下都是相同的类别,则应在“字段 - 表”中将类别设置为FK列。如果有一点机会,那么一个领域的类别可能因环境而异,你不应该...
与教师相同:如果教师被绑定到一个单独的类别,则在教师表中设置一个FK列,否则不要。
最灵活的是,您将至少拥有一个映射表:
(SQL Server语法)
CREATE TABLE TeacherFieldCategory
(
--A primary key to identify this row. This is not needed actually, but it will serve as clustered key index as a lookup index...
TeacherFieldCategoryID INT IDENTITY NOT NULL CONSTRAINT PK_TeacherFieldCategory PRIMARY KEY
--Must be set
,TeacherID INT NOT NULL CONSTRAINT FK_TeacherFieldCategory_TeacherID FOREIGN KEY REFERENCES Teacher(TeacherID)
--Field may be left NULL
,FieldID INT NULL CONSTRAINT FK_TeacherFieldCategory_FieldID FOREIGN KEY REFERENCES Field(FieldID)
--Must be set. This makes sure, that a teacher ever has a category and - if the field is set - the field will have a category
,CategoryID INT NOT NULL CONSTRAINT FK_TeacherFieldCategory_CategoryID FOREING KEY REFERENCES Category(CategoryID)
);
--This unique index will ensure, that each combination will exist only once.
CREATE UNIQUE INDEX IX_TeacherFieldCategory_UniqueCombination ON TeacherFieldCategory(TeacherID,FieldID,CategoryID);
将映射表FieldCategory和此表通过外键映射到上面的映射表可能是一个更好的概念。这样做可以避免无效的字段类别组合。
希望这会有所帮助......