如何使复合键唯一?
Posted
技术标签:
【中文标题】如何使复合键唯一?【英文标题】:How to make a composite key to be unique? 【发布时间】:2012-08-02 08:19:31 【问题描述】:我正在为一所学校的学生创建一个数据库。这是我目前所拥有的:
如果您不喜欢阅读,请跳至“简而言之”部分
问题是我对这个设计不满意。我希望grade
、subgrade
和id_class
的组合是唯一的,并作为学生表的主键。
我可以删除 student_id
并从 3 中创建一个复合键,但我也不想要这样。也许我应该创建另一个表,比如说combination_id
,其中grade
、subgrade
和id_class
是外键,还有一个额外的列comb_id
作为表的ID。所有的列都将是主键。但问题是这 3 列仍然可以重复,因为那个额外的列 (comb_id
)。例如,我可以拥有相同的 grade
、subgrade
和 class_id
,但不同的 comb_id
由于表的 4 列 (combination_id
) 的复合键,这将使行有效。
简而言之,我希望 students_id
保持表的唯一主键,但作为另一个表的外键,该表是 grades
、subgrade
和 class_id
的独特组合。
如果我不够清楚,请在下面的 cmets 中提问,并提前感谢您。
PS 我很抱歉这个难以描述的标题,但我不擅长命名
编辑 1:
为了更清楚:
grade
可以是 1 到 12
subgrade
可以是 a 到 j
id_class
可以是 1 到 30,是你的班级号码
所以一个学生可以来自 7b 班级,他的班级人数 - 5
【问题讨论】:
我不明白,一个班的所有学生都应该有不同的成绩吗? 当学生换班时你会怎么做,或者这种情况永远不会发生?student_id
列有什么问题?
学生是否只有一个班级,如小学/初中/幼儿学校?
@Jodrell 我已经编辑了我的问题,以便更清楚地了解这些列。我希望 student_id
成为另一个表中的 FK,其中包含用作其中复合键的那 3 列。如果您仍有问题,请询问
【参考方案1】:
不要混淆唯一键和主键的概念。您可以很好地添加一个unique key 跨越三列grades
、subgrade
和class_id
。这样一来,没有两行could have 这三列的值相同。当您写到您不想将这三个作为复合主键时,我不确定复合唯一补充键是否会更好。如果不是,您必须说明何时可以接受复合键。
要创建唯一键,可以使用以下 SQL statement:
ALTER TABLE students ADD UNIQUE gsc (grades, subgrade, class_id);
gsc
这个词只是我从关键列的首字母组成的一个名字;使用您想要的任何名称,因为它几乎不重要,除非您想在某些 EXPLAIN
输出或类似输出中识别密钥。
【讨论】:
谢谢,我会试试的,我可能会将人们与grade
、subgrade
和 id_class
的名称混淆,但在我的国家,教育系统是不同的。
好的,我试过了,但是当我创建了所有 3 列 UNIQUE
时,我收到了重复条目的错误。我有很多 grades
3 但它们有不同的 subgrades
所以它将它们视为单独的 unique
键。还有什么是补充?
不要使所有 thre 列本身唯一,而是一起使:ALTER TABLE students ADD UNIQUE gsc (grades, subgrade, class_id)
。 gsc
只是一个名字,随便你怎么用。然后,只有三个都相同时才会出现重复。我使用了 supplementary 这个术语而不是 primary:使用此命令定义的键不是主键,但仍然是唯一的。【参考方案2】:
我不完全清楚你为什么想要你所描述的,但我会以以下方式查看模型......
你有学生 - 它们是不同的实体,而不是其他实体的组合 - 他们有自己的属性;姓名、出生日期等
你有课程 - 这些是学生群体 - 每个学年同一个“班级”有不同的学生在里面 - 他们也有自己的属性;等级、次等级等
您的模型中有一个我通常不会使用的额外属性 - 如果一个班级有 20 名学生,每个学生都使用从 1 到 20 的次要 id 进行标识
这会给我以下维度表
Student Class Grade SubGrade
----------------------- ------------------------ ----------------- -----------------
id INT PK id INT PK id INT PK id INT PK
first_name VARCHAR(45) name VARCHAR(45) name VARCHAR(45) name VARCHAR(45)
last_name VARCHAR(45) grade_id INT FK desc VARCHAR(45) desc VARCHAR(45)
etc, etc subgrade_id INT FK etc, etc etc, etc
Class
表将对(grade_id, subgrade_id)
具有唯一约束,因此只有一个类可以是7b
。
然后你需要使用事实表将学生与他们的班级联系起来......
Class_Membership
-----------------------
id INT PK
student_id INT FK
class_id INT FK
academic_year INT
如果一个学生在任何一个学年都只能上一个班级,那么您可以对 (student_id, academic_year)
设置一个独特的限制条件。
或者,您可以在Class
表中填写学年。这意味着您每年都会重复相同的课程,但在某些年份可能不存在课程7g
(例如,因为那一年的学生较少)。
同样,您可以让学生在年中从7b
转到7c
。在这种情况下,Class_Membership
表可能有一个start_date
字段,也可能有一个end_date
字段。
然而,这些都不是直接创建id_class
字段(1-20 代表一个有 20 名学生的班级)。就我个人而言,我不会有这样的字段,Class_Membership
表中的 id
字段可以提供大部分相同的功能,可能还有其他功能。但是,如果需要,您可以简单地将其添加到Class_Membership
表中...
Class_Membership
-----------------------
id INT PK
student_id INT FK
class_id INT FK
academic_year INT
class_member_id INT
那么您还可以对 (academic_year, class_id, class_member_id)
设置唯一约束。
这里有很大的灵活性,具体取决于您的实际模型和您的特定需求。但希望这个例子对你来说是一个好的开始;列出实体的维度表,以及将这些实体关联在一起和/或进一步描述实体的事实表(或多个表)。
【讨论】:
当您询问当前的模式时,我将在这里添加我的想法。 @Bosak,在我的理解中,“路基”只是一个区分同一年级不同班级的字母。因此,虽然等级和路基标识了一个类,但路基本身并不是一个真正的实体。您很少会对“所有具有路基 b 的类”感兴趣,甚至对存储所有这些 b 类的公共属性更不感兴趣,对吧?在这种情况下,我会删除 SubGrade 表。【参考方案3】:alter table <TableName> add constraint <ConstraintName> unique(<col1>, <col2>)
Modified the answer due to syntax mistakes. Mentioned above is correct.
【讨论】:
以上是关于如何使复合键唯一?的主要内容,如果未能解决你的问题,请参考以下文章