SQL:使用2个不同的auto_increment创build一个关系表
我有2个表,都有自己的自动递增的ID,这当然是主键。
当我想创build第三个表来build立这两个表之间的关系时,我总是有一个错误。
首先是你可以只有一个自动递增的列,第二个是我从这两个删除auto_increment语句时发生的,所以sql不允许我把它们作为外键,因为types匹配失败。
有没有办法可以创build一个关系表,而不会丢失自动递增function?
另一个可能的(但不是优先的)解决scheme可能是第一个表中有另一个主键,当然是用户的用户名,而不是自动增量语句。 这是不可避免的吗?
提前致谢。
概念
你误解了一些基本的概念,由此产生了困难。 我们必须首先解决这些概念,而不是像你所感知的那样问题,因此,你的问题就会消失。
自动递增的ID,这当然是主键。
不,他们不是。 这是一个常见的误解。 问题将得到保证。
ID
字段不能是英文或技术或关系意义上的主键。
-
当然,在SQL中,可以将任何字段声明为
PRIMARY KEY
,但这不会将其转换为英文,技术或关系意义上的主键。 你可以命名吉娃娃“Rottweiller”,但这并不会变成Rottweiller,它仍然是一个吉娃娃。 像任何语言一样,SQL只是执行你给它的命令,它并不理解PRIMARY KEY
来表示关系,它只是在列(或字段)上打一个唯一的索引。 -
问题是,既然你已经声明了
ID
是一个PRIMARY KEY
,你可以把它看作一个主键,并且你可能期望它具有一些主键的特性。 除了ID 值的唯一性,它没有任何好处。 它没有一个主键的特性,也没有任何关系键。 这不是英语,技术或关系意义上的关键。 通过声明一个非键是一个键,你只会迷惑自己,你会发现,只有当用户抱怨表中有重复时,才会有一些错误。
关系表必须具有行唯一性
ID
字段上的PRIMARY KEY
不提供行唯一性。 因此,它不是一个包含行的关系表,如果不是,那么它就是一个包含logging的文件。 它没有任何完整性或权力(在这个阶段你只会意识到join的力量),或者说关系数据库中的表具有的速度。
执行此代码 (MS SQL 2008)并自行certificate。 请不要简单阅读本文并理解它,然后继续阅读本答复的其余部分, 在进一步阅读之前必须执行此代码 。 它具有治疗价值。
CREATE TABLE dumb_file ( id INT NOT NULL IDENTITY PRIMARY KEY, name_first CHAR(30) NOT NULL, name_last CHAR(30) NOT NULL ) INSERT dumb_file VALUES ( "Mickey", "Mouse" ) -- succeeds INSERT dumb_file VALUES ( "Mickey", "Mouse" ) -- succeeds, but not intended INSERT dumb_file VALUES ( "Mickey", "Mouse" ) -- succeeds, but not intended SELECT * FROM dumb_file
注意你有重复的行 。 关系表需要有唯一的行 。 进一步certificate你没有关系表,或者没有关系表的任何一个质量。
注意,在你的报告中唯一唯一的是ID
字段,没有用户关心,没有用户看到,因为它不是数据,这是一些非常愚蠢的“老师”告诉你放在一些额外的废话每个文件。 你有logging唯一性,但不是行唯一性。
根据数据(真实数据减去无关的加法),数据name_last
和name_first
可以不存在ID
字段。 一个人的名字和姓氏的前额上没有标识。
你使用的第二件事让你感到困惑的是AUTOINCREMENT.
如果您正在实施不具有关系function的logging归档系统,那么确实有帮助,插入logging时不必编写增量。 但是如果你正在实现一个关系型数据库,它根本没有任何用处,因为你永远不会使用它。 SQL中有许多function,大多数人从不使用。
纠正措施
那么,为了获得关系表的一些品质和优势,你如何将那些充满重复行的dumb_file升级,提升到关系表? 这有三个步骤。
-
你需要了解钥匙
- 而且由于我们已经从20世纪70年代的ISAM文件发展到关系模型 ,所以您需要了解关系密钥 。 也就是说,如果您希望获得关系数据库的好处(完整性,function,速度)。
EF Cood博士在他的RM中宣称:
一个关键是由数据组成的
和
表中的行必须是唯一的
你的“钥匙”不是由数据组成的。 这是一些额外的非数据寄生虫,是由于您感染了您的“老师”的疾病而引起的。 认识到这一点,并让自己有充分的心智能力,上帝给你(注意,我不要求你孤立或分割或抽象的思想,数据库中的所有元素必须相互融合)。 从数据中构成一个真正的密钥,并且只从数据中获得。 在这种情况下,只有一个可能的键:
(name_last, name_first).
-
试试这个代码 ,在数据上声明一个唯一的约束:
CREATE TABLE dumb_table ( id INT NOT NULL IDENTITY PRIMARY KEY, name_first CHAR(30) NOT NULL, name_last CHAR(30) NOT NULL CONSTRAINT UK UNIQUE ( name_last, name_first ) ) INSERT dumb_table VALUES ( "Mickey", "Mouse" ) -- succeeds INSERT dumb_table VALUES ( "Mickey", "Mouse" ) -- fails, as intended INSERT dumb_table VALUES ( "Minnie", "Mouse" ) -- succeeds SELECT * FROM dumb_table
现在我们有行独特性 。 这是大多数人发生的顺序:他们创build一个允许模糊的文件; 他们不知道为什么愚蠢是出现在下降; 用户尖叫; 他们调整文件,并添加一个索引,以防止愚蠢的; 他们去下一个错误修复。 (他们可能正确或不正确,这是一个不同的故事。)
-
第二级。 思考那些超越固定思维的人。 既然我们现在有排队的唯一性,那么天堂的名字就是
ID
字段的目的,我们为什么还要有呢? 哦,因为吉娃娃叫Rotty,我们不敢碰它。这是一个
PRIMARY KEY
的声明是错误的,但它仍然存在,造成混淆和错误的期望。 唯一真正的钥匙是(name_last, name_fist),
这是一个备用钥匙在这一点上。因此
ID
字段完全是多余的; 支持它的指数也是如此; 愚蠢的AUTOINCREMENT
也是如此; 这是一个PRIMARY KEY
的虚假声明也是如此; 任何你对它的期望都是错误的。因此删除多余的
ID
字段。 试试这个代码 :CREATE TABLE honest_table ( name_first CHAR(30) NOT NULL, name_last CHAR(30) NOT NULL CONSTRAINT PK PRIMARY KEY ( name_last, name_first ) ) INSERT honest_table VALUES ( "Mickey", "Mouse" ) -- succeeds INSERT honest_table VALUES ( "Mickey", "Mouse" ) -- fails, as intended INSERT honest_table VALUES ( "Minnie", "Mouse" ) -- succeeds SELECT * FROM honest_table
工作得很好,按预期工作,没有多余的字段和索引。
请记住这一点,并做好每一次。
假教师
在这些最后时刻,我们会有很多这样的build议。 注意,根据本文的详细证据,传播ID
列的“教师”根本不理解关系模型或关系数据库。 尤其是写书的人。
事实certificate,他们被困在1970年前的ISAM技术中。 这就是他们所能理解的,这就是他们所能教的。 他们使用SQL数据库容器,以方便访问,恢复,备份等,但内容是纯粹的logging归档系统,没有关系完整性,功耗或速度。 AFAIC,这是一个严重的欺诈行为。
当然,除了ID
字段之外,还有几个关键或不关联的概念,这些概念结合在一起,使我形成了这样一个严重的结论。 这些其他项目超出了这篇文章的范围。
一个特殊的白痴现在正在对第一范式进行攻击。 他们属于庇护所。
回答
现在问题的其余部分。
有没有办法可以创build一个关系表,而不会丢失自动递增function?
这是一个自相矛盾的句子。 我相信你会从我的解释中理解,关系表不需要 AUTOINCREMENT
“function”。 如果该文件具有AUTOINCREMENT
,则不是关系表。
AUTOINCREMENT
仅适用于一件事情:如果且仅当您希望在SQL数据库容器中创buildExcel电子表格,则在顶部填充名为A,
B,
和C,
字段,并在左侧logging数字。 从数据库的angular度来看,这是数据平面化的结果,而不是数据的来源 ,这是组织的(规范化)。
另一个可能的(但不是优先的)解决scheme可能是第一个表中有另一个主键,当然是用户的用户名,而不是自动增量语句。 这是不可避免的吗?
在技术工作上,我们并不在乎喜好,因为这是主观的,而且总是在变化。 我们关心技术的正确性,因为这是客观的,而且不会改变。
是的,这是不可避免的。 因为这只是一个时间问题; 错误的数量; “不能做”的号码; 用户尖叫的次数,直到你面对事实,克服你的虚假陈述,并认识到:
-
要确保用户行是唯一的,唯一的方法是声明一个
UNIQUE
约束 -
并删除用户文件中的
user_id
或id
-
将
user_name
升级为PRIMARY KEY
是的,因为你的第三张桌子的整个问题,不巧合,然后被淘汰。
第三个表是关联表 。 唯一所需的键(主键)是两个父键主键的组合。 这确保了由它们的键标识的行的唯一性,而不是它们的IDs.
我正在向你提出警告,因为那些向你教授实现ID
字段错误的“老师”教导了在关联表中实现ID
字段的错误,正如普通表一样,它是多余的,不起任何作用,介绍重复,造成混乱。 这是多余的,因为提供的两把钥匙已经在那里,把我们盯在脸上。
由于他们不了解RM或关系术语,因此他们调用关联表“链接”或“映射”表。 如果他们有一个ID
字段,他们实际上是文件。
查找表
ID
字段是特别愚蠢的做的查找或参考表。 他们中的大多数具有可识别的代码,因为代码是(应该是)唯一的,所以不需要枚举代码列表。
另外,将子表中的代码设置为FK,这是一件好事:代码更有意义,并且通常可以节省不必要的连接:
SELECT ... FROM child_table -- not the lookup table WHERE gender_code = "M" -- FK in the child, PK in the lookup
代替:
SELECT ... FROM child_table WHERE gender_id = 6 -- meaningless to the maintainer
或更糟:
SELECT ... FROM child_table C -- that you are trying to determine JOIN lookup_table L ON C.gender_id = L.gender_id WHERE L.gender_code = "M" -- meaningful, known
请注意,这是不能避免的:您需要查找代码的唯一性和描述的唯一性。 这是防止两列中的每一个重复的唯一方法:
CREATE TABLE gender ( gender_code CHAR(2) NOT NULL, name CHAR(30) NOT NULL CONSTRAINT PK PRIMARY KEY ( gender_code ) CONSTRAINT AK UNIQUE ( name ) )
完整的例子
从你的问题的细节,我怀疑你有SQL语法和FK定义问题,所以我会给你需要的整个解决scheme作为一个例子(因为你没有给出文件定义):
CREATE TABLE user ( -- Typical Identifying Table user_name CHAR(16) NOT NULL, -- Short PK name_first CHAR(30) NOT NULL, -- Alt Key.1 name_last CHAR(30) NOT NULL, -- Alt Key.2 birth_date DATE NOT NULL -- Alt Key.3 CONSTRAINT PK -- unique user_name PRIMARY KEY ( user_name ) CONSTRAINT AK -- unique person identification PRIMARY KEY ( name_last, name_first, birth_date ) ) CREATE TABLE sport ( -- Typical Lookup Table sport_code CHAR(4) NOT NULL, -- PK Short code name CHAR(30) NOT NULL -- AK CONSTRAINT PK PRIMARY KEY ( sport_code ) CONSTRAINT AK PRIMARY KEY ( name ) ) CREATE TABLE user_sport ( -- Typical Associative Table user_name CHAR(16) NOT NULL, -- PK.1, FK sport_code CHAR(4) NOT NULL, -- PK.2, FK start_date DATE NOT NULL CONSTRAINT PK PRIMARY KEY ( user_name, sport_code ) CONSTRAINT user_plays_sport_fk FOREIGN KEY ( user_name ) REFERENCES user ( user_name ) CONSTRAINT sport_occupies_user_fk FOREIGN KEY ( sport_code ) REFERENCES sport ( sport_code ) )
在那里, PRIMARY KEY
声明是诚实的,它是一个主键; 没有ID;
没有AUTOINCREMENT;
没有额外的指标; 没有重复的行 ; 没有错误的期望; 没有相应的问题。
数据模型
这里是数据模型去定义。
-
示例用户体育数据模型
-
如果你不习惯这个符号,请注意,每一个小刻度,刻度和标记,实线与虚线,正方形与圆angular,都是非常具体的。 请参阅IDEF1X表示法 。
-
一张图片胜过千言万语; 在这种情况下,一个标准投诉的图片比这更值得一提; 坏的一个是不值得它所绘制的文件。
-
请仔细检查动词词组,它们包含一组谓词。 Predicates的其余部分可以直接从模型中确定。 如果不清楚,请询问。