1 概念
您误解了一些基本概念,因此造成了困难。我们必须首先解决概念,而不是您认为的问题,因此,您的问题将消失。
自动递增的 ID,当然是主键。
不,他们不是。这是一个普遍的误解。并且肯定会出现问题。
ID 字段不能是英语、技术或关系意义上的主键。
-
当然,在 SQL 中,您可以将 any 字段声明为 PRIMARY KEY,但这不会神奇地将其转换为英语、技术或关系意义上的主键。您可以将吉娃娃命名为“罗威纳犬”,但这并不能将其变成罗威纳犬,它仍然是吉娃娃。像任何语言一样,SQL 只是执行你给它的命令,它不理解 PRIMARY KEY 的意思是关系,它只是在列(或字段)上敲击一个唯一索引。
-
问题是,既然您声明 ID 是PRIMARY KEY,您认为它是主键,您可能期望它具有主键的某些特性。除了 ID value 的唯一性之外,它没有任何好处。它没有主键或任何类型的关系键的品质。它不是英语、技术或关系意义上的 Key。将非键声明为键,只会让自己感到困惑,只有当用户抱怨表中有重复时,才会发现有什么可怕的错误。
2 关系模型
2.1 关系表必须具有行唯一性
ID 字段上的PRIMARY KEY 不提供行 唯一性。因此它不是一个包含行的关系表,如果不是,那么它就是一个包含记录的文件。它不具备关系数据库中的表所具有的完整性、能力(在此阶段您将只知道连接能力)或速度。
-
执行this code (MS SQL) 并向自己证明。请不要简单地阅读并理解它,然后继续阅读此答案的其余部分,在进一步阅读之前必须执行此代码。有治疗价值。
-- [1] Dumb, broken file
-- Ensures unique RECORDS, allows duplicate ROWS
CREATE TABLE dumb_file (
id INT IDENTITY PRIMARY KEY,
name_first CHAR(30),
name_last CHAR(30)
)
INSERT dumb_file VALUES
( 'Mickey', 'Mouse' ),
( 'Mickey', 'Mouse' ),
( 'Mickey', 'Mouse' )
SELECT *
FROM dumb_file
请注意您有重复的行。关系表必须具有唯一的行。进一步证明您没有关系表或任何关系表的性质。
请注意,在您的报告中,唯一独特的是 ID 字段,没有用户关心,没有用户看到,因为它不是数据,一些非常愚蠢的“老师”是一些额外的废话告诉你把每个文件。您有 record 唯一性,但没有 row 唯一性。
在数据方面(真实数据减去额外的添加),数据name_last和name_first可以在没有ID字段的情况下存在。一个人有名字和姓氏,但额头上没有盖章。
您使用的第二个让您感到困惑的东西是AUTOINCREMENT. 如果您正在实施一个没有关系功能的记录归档系统,当然,这很有帮助,您不必在插入记录时编写增量代码。但是如果你正在实现一个关系数据库,它根本就没有任何用处,因为你永远不会使用它。 SQL 中有很多功能是大多数人从不使用的。
2.2 纠正措施
那么,您如何将充满重复行的dumb_file 升级、提升到关系表,以获得关系表的一些品质和好处?这需要三个步骤。
-
你需要了解钥匙
由于我们已经从 1970 年代的 ISAM 文件发展到 关系模型,因此您需要了解 关系键。也就是说,如果您希望获得关系数据库的优势(完整性、功能、速度)。
在 Codd 的关系模型中:
密钥由数据组成
和
表中的行必须是唯一的
您的“钥匙”不是由数据组成的。它是一些额外的、非数据的寄生虫,是由于你感染了你的“老师”的疾病而引起的。认清这一点,并让自己拥有上帝赋予你的全部心智能力(请注意,我不要求你以孤立、支离破碎或抽象的方式思考,数据库中的所有元素必须相互整合)。
由数据构成一个真正的密钥,并且仅由数据构成。在这种情况下,只有一个可能的 Key:(name_last, name_first).
-
Try this code,声明对数据的唯一约束:
-- [2] dumb_file fixed, elevated to table, prevents duplicate rows
-- still dumb
CREATE TABLE dumb_table (
id INT IDENTITY PRIMARY KEY,
name_first CHAR(30),
name_last CHAR(30),
CONSTRAINT UK
UNIQUE ( name_last, name_first )
)
INSERT dumb_table VALUES
( 'Mickey', 'Mouse' ),
( 'Minnie', 'Mouse' )
SELECT *
FROM dumb_table
INSERT dumb_table VALUES
( 'Mickey', 'Mouse' )
现在我们有了行唯一性。这是发生在大多数人身上的顺序:他们创建一个允许欺骗的文件;他们不知道为什么会出现在下拉列表中的骗子;用户尖叫;他们调整文件并添加索引以防止欺骗;他们去下一个错误修复。 (他们这样做可能正确与否,那是另一回事。)
-
第二层。对于那些思考超出固定范围的人。既然我们现在有行唯一性,那么 ID 字段的目的到底是什么,我们为什么还要拥有它???哦,因为吉娃娃叫Rotty,我们不敢碰它。
它是PRIMARY KEY 的声明是错误的,但它仍然存在,导致混乱和错误的期望。唯一真正的密钥是(name_last, name_fist),,此时它是备用密钥。
因此ID 字段是完全多余的;支持它的索引也是如此;愚蠢的AUTOINCREMENT也是如此;错误声明它是PRIMARY KEY 也是如此;你对它的任何期望都是错误的。
因此删除多余的ID 字段。 Try this code:
-- [3] Relational Table
-- Now that we have prevented duplicate data, the id field
-- AND its additional index serves no purpose, it is superfluous,
-- like an udder on a bull. If we remove the field AND the
-- supporting index, we obtain a Relational table.
CREATE TABLE relational_table (
name_first CHAR(30),
name_last CHAR(30),
CONSTRAINT PK
PRIMARY KEY ( name_last, name_first )
)
INSERT relational_table VALUES
( 'Mickey', 'Mouse' ),
( 'Minnie', 'Mouse' )
SELECT *
FROM relational_table
INSERT relational_table VALUES
( 'Mickey', 'Mouse' )
工作正常,按预期工作,没有多余的字段和索引。
请记住这一点,并且每次都做对。
2.3 假教师
在这些末世,正如我们所建议的,我们将拥有许多这样的时代。请注意,传播ID 列的“老师”,凭借本文中的详细证据,根本不了解关系模型或关系数据库。尤其是那些写书的人。
正如所证明的,他们被困在 1970 年之前的 ISAM 技术中。这就是他们所了解的一切,这就是他们所能教的一切。他们使用 SQL 数据库容器,以便于访问、恢复、备份等,但内容是纯粹的记录归档系统,没有关系完整性、功能或速度。 AFAIC,这是严重的欺诈行为。
当然,除了ID 字段之外,还有几个关键的Relational-or-not 概念,放在一起,使我形成如此严肃的结论。这些其他项目超出了本文的范围。
目前有一对特定的白痴正在对第一范式发起攻击。他们属于庇护所。
3 解决方案
现在回答你剩下的问题。
3.1 答案
有没有一种方法可以在不丢失自动增量功能的情况下创建关系表?
这是一个自相矛盾的句子。我相信你会从我的解释中明白,AUTOINCREMENT“功能”的关系表不需要;如果文件有AUTOINCREMENT,则它不是关系表。
AUTOINCREMENT 或 IDENTITY 仅适用于一件事:当且仅当您想在 SQL 数据库容器中创建一个 Excel 电子表格,其中包含名为 A, B, 和 C, 的字段在顶部,并在左侧记录数字。在数据库术语中,这是 SELECT 的 result,数据的扁平视图,不是数据的来源,它是有组织(标准化)。
另一种可能(但不是首选)的解决方案可能是第一个表中有另一个主键,它是用户的用户名,当然不是自动递增语句。这是不可避免的吗?
在技术工作中,我们不关心偏好,因为这是主观的,并且一直在变化。我们关心技术上的正确性,因为这是客观的,不会改变。
是的,这是不可避免的。因为这只是时间问题;错误数量; “不能做”的数量;用户尖叫的次数,直到你面对事实,克服你的虚假声明,并意识到:
是的,因为您与第三张表的整个问题,并非巧合,然后被消除了。
第三个表是关联表。唯一需要的键(主键)是两个父主键的组合。这确保了 行 的唯一性,这些行由它们的键标识,而不是由它们的 IDs.
我警告你,因为那些教你实现ID字段错误的“老师”,教你在关联表中实现ID字段的错误,就像普通表一样,它是多余的,没有任何用处,引入重复,并引起混乱。而且它是双重多余的,因为提供的两把钥匙已经在那里,盯着我们的脸。
由于他们不理解 RM 或关系术语,他们将关联表称为“链接”或“映射”表。如果它们有 ID 字段,它们实际上就是文件。
3.2 查找表
ID 字段对于查找表或参考表来说是特别愚蠢的事情。它们中的大多数都有可识别的代码,无需枚举其中的代码列表,因为代码是(应该)唯一的。
ENUM 同样愚蠢,但出于不同的原因:它将您锁定在一种反 SQL 方法中,即不符合标准的“SQL”中的“功能”。
此外,将子表中的代码作为 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 )
)
3.3 完整示例
从你问题中的细节来看,我怀疑你有SQL语法和FK定义问题,所以我会给出你需要的整个解决方案作为例子(因为你没有给出文件定义):
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; 没有额外的索引;没有重复的行;没有错误的期望;没有相应的问题。
3.4 关系数据模型
这是与定义一起使用的数据模型。
-
作为PDF
-
如果您不习惯符号,请注意,每一个小勾号、缺口和标记,实线与虚线,方角与圆角,都意味着非常具体的东西。参考IDEF1X Notation。
-
一张图片胜过千言万语;在这种情况下,标准投诉图片的价值远不止于此;一张糟糕的纸不值得画它。
-
请仔细检查动词短语,它们包含一组谓词。谓词的其余部分可以直接从模型中确定。如果不清楚,请询问。