SQL:使用2个不同的auto_increment创建关系表

Ahm*_*tan 6 mysql sql relational-database auto-increment

我有2个表,都有自己的自动递增ID,这当然是主键.

当我想创建第3个表来建立这两个表之间的关系时,我总是有一个错误.

第一个是关于你只能有一个自动递增的列,第二个是当我从那些2中删除auto_increment语句时发生的,因此sql不允许我将它们作为外键,因为类型匹配失败.

有没有办法可以创建关系表而不会丢失自动增量功能?

另一种可能的(但不是优选的)解决方案可能是第一个表中有另一个主键,当然是用户的用户名,而不是自动增量语句.这是不可避免的吗?

提前致谢.

Per*_*DBA 15

概念

你误解了一些基本概念,并且由此产生了困难.我们必须首先解决这些概念,而不是你所认识到的问题,因此,你的问题就会消失.

自动递增的ID,当然是主键.

不,他们不是.这是一种常见的误解.并且保证问题随之而来.

一个ID字段不能以英文或技术或关系感官主键.

  • 当然,在SQL中,您可以将任何字段声明为a PRIMARY KEY,但这并不会将其神奇地转换为英语,技术或关系意义上的主键.你可以将奇瓦瓦命名为"Rottweiller",但这并没有将它变成罗威威尔,它仍然是奇瓦瓦.像任何语言一样,SQL只是执行你给它的命令,它不能理解PRIMARY KEY为关系,它只是在列(或字段)上敲击一个唯一索引.

  • 问题是,既然你已经宣布ID是一个PRIMARY KEY,你认为它作为一个主键,你可以期望它有一些主键的特质.除了ID 的唯一性之外,它没有任何好处.它没有主键的任何特性,也没有任何关系密钥.它不是英语,技术或关系意义上的关键.通过声明非密钥成为密钥,您只会混淆自己,并且只有当用户抱怨表中的重复时才会发现存在严重错误.

关系表必须具有唯一性

字段PRIMARY KEY上的A ID不提供唯一性.因此,它不是包含行的Relational表,如果不是,则它是包含记录的文件.它没有任何完整性或功能(在此阶段,您将只知道连接功率)或速度,即Relational数据库中的表具有.

执行此代码(MS SQL 2008)并向您自己证明.请不要简单地阅读并理解它,然后继续阅读本答案的其余部分,必须在进一步阅读之前执行此代码.它具有疗效价值.

    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
Run Code Online (Sandbox Code Playgroud)

请注意,您有重复的.关系表需要具有唯一的.进一步证明您没有关系表或任何一个关系表.

请注意,在你的报告中,唯一独一无二的是ID字段,没有用户关心,没有用户看到,因为它不是数据,这是一些额外的废话,一些非常愚蠢的"老师"告诉你放入每个文件.您具有记录唯一性,但不具有唯一性.

就数据而言(实际数据减去无关的附加物),数据name_last并且name_first可以在没有该ID字段的情况下存在.一个人的名字和姓氏没有在他们的额头上盖上身份证.

您正在使用的第二件事就是AUTOINCREMENT. 如果您正在实现一个没有关系功能的记录文件系统,当然,这很有用,您不必在插入记录时对增量进行编码.但是,如果您正在实现一个关系数据库,它根本没有用处,因为您永远不会使用它.SQL中有许多功能,大多数人从不使用.

纠正措施

那么如何将充满重复行的dumb_file升级,提升到Relational表,以获得Relational表的一些特性和优点?这有三个步骤.

  1. 你需要了解Keys

    • 既然我们已经从1970年代的ISAM文件发展到关系模型,那么你需要了解关系密钥.也就是说,如果您希望获得关系数据库的好处(完整性,功能,速度).

    EF Coo​​d博士在他的RM中宣称:

    密钥由数据组成

    表中的行必须是唯一的

    您的"密钥"不是由数据组成的.这是一些额外的非数据寄生虫,由您感染"老师"的疾病引起.认识到这一点,让自己拥有上帝给你的全部心智能力(注意我不要求你以孤立或零碎或抽象的方式思考,数据库中的所有元素必须相互整合).从数据中组成一个真正的密钥,并且只从数据中组成.在这种情况下,只有一个可能的密钥:(name_last, name_first).

  2. 试试这段代码,声明对数据的唯一约束:

         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
    
    Run Code Online (Sandbox Code Playgroud)

    现在我们有行唯一性.这是大多数人发生的序列:他们创建一个允许欺骗的文件; 他们不知道为什么欺骗会出现在下拉中; 用户尖叫; 他们调整文件并添加索引以防止欺骗; 他们进入下一个bug修复.(他们可能正确或不正确,这是一个不同的故事.)

  3. 第二级.思考那些超越修复的人 - 它.既然我们现在有行唯一性,天堂的名字就是这个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
    
    Run Code Online (Sandbox Code Playgroud)

    工作正常,按预期工作,没有无关的字段和索引.

    请记住这一点,并且每次都做得对.

假教师

在这些结束时间,按照建议,我们将拥有其中许多.请注意,ID根据本文中的详细证据,传播列的"教师" 根本不理解关系模型或关系数据库.特别是那些写书的人.

如证据所示,他们陷入了1970年以前的ISAM技术.这就是他们所理解的一切,而这就是他们所能教导的一切.它们使用SQL数据库容器,以便于访问,恢复,备份等,但内容是纯记录文件系统,没有关系完整性,功能或速度.AFAIC,这是一个严重的欺诈行为.

ID当然,除了字段之外,还有几个关键的关系或非关键概念,它们合在一起,使我形成如此严肃的结论.其他项目超出了本文的范围.

一对特殊的白痴目前正在对First Normal Form进行攻击.他们属于庇护所.

回答

现在问你的其余部分.

有没有办法可以创建关系表而不会丢失自动增量功能?

这是一个自相矛盾的句子.我相信你会从我的解释明白,关系表也没有必要AUTOINCREMENT"特色"; 如果文件有AUTOINCREMENT,则它不是Relational表.

AUTOINCREMENT仅适用于一件事:当且仅当您想要在SQL数据库容器中创建Excel电子表格时,请填充名称A, B,C,顶部的字段,并在左侧记录数字.在数据库术语,即结果是SELECT,数据的平面视图,即数据的,这是组织的(归一化).

另一种可能的(但不是优选的)解决方案可能是第一个表中有另一个主键,当然是用户的用户名,而不是自动增量语句.这是不可避免的吗?

在技​​术工作中,我们不关心偏好,因为这是主观的,并且它一直在变化.我们关心技术的正确性,因为这是客观的,并且不会改变.

是的,这是不可避免的.因为这只是时间问题; 错误数量; 数量"不能dos"; 用户尖叫的数量,直到你面对事实,克服你的虚假声明,并意识到:

  • 确保用户唯一的唯一方法是user_names是唯一的,就是声明UNIQUE对它的约束

  • 并摆脱user_idid在用户文件中

  • 促进user_namePRIMARY 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
Run Code Online (Sandbox Code Playgroud)

代替:

    SELECT ...
        FROM child_table
        WHERE gender_id = 6        -- meaningless to the maintainer
Run Code Online (Sandbox Code Playgroud)

或者更糟:

    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
Run Code Online (Sandbox Code Playgroud)

请注意,这是一件谁都无法回避:你需要查找代码的唯一性独特性的描述.这是防止两列中每一列重复的唯一方法:

    CREATE TABLE gender (
        gender_code  CHAR(2)  NOT NULL,
        name         CHAR(30) NOT NULL

        CONSTRAINT PK 
            PRIMARY KEY ( gender_code )

        CONSTRAINT AK 
            UNIQUE ( name )
        )
Run Code Online (Sandbox Code Playgroud)

完整的例子

根据您问题中的详细信息,我怀疑您有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 )
        )
Run Code Online (Sandbox Code Playgroud)

在那里,PRIMARY KEY声明是诚实的,它是一个主键; 没有ID;没有AUTOINCREMENT;没有多余的指标; 没有重复的 ; 没有错误的期望; 没有相应的问题.

数据模型

以下是与定义一起使用的数据模型.

  • 示例用户运动数据模型

  • 如果您不习惯乐谱,请注意每个小刻度,刻痕和标记,实线与虚线,方形与圆角,意味着非常具体的东西.请参阅IDEF1X表示法.

  • 一张图片胜过千言万语; 在这种情况下,标准投诉图片的价值不止于此; 一个坏的不值得它所用的论文.

  • 请仔细检查动词短语,它们包含一组谓词.其余的Predicates可以直接从模型中确定.如果不清楚,请询问.

  • @Hamster_NL。(一)谢谢。选票在这种“民主”中很重要。(b) 我根据上下文回答问题,没有必要通过拜访来吓唬那些要求十字架的热心初学者。(c) **自动增量不是键**,在任何表中,**它[保证重复行](http://stackoverflow.com/a/29726132/484814)**。识别人员的标准(例如护照信息)位于[**此模型的底部**](http://www.softwaregems.com.au/Documents/Student%20Resolutions/Bill%20of%20Materials。 pdf)。 (3认同)
  • 我读过很多关于数据库的精彩回复,但是在创建“联系人数据库”时,您将如何定义 PK?联系人数据库将在全球范围内使用,因此仅对名字和姓氏进行限制将会出现问题。您将使用多少个字段来创建 PK,还是“自动 ID”更合适? (2认同)
  • @Hamster_NL.(d)在真实RDb中记录它意味着BirthPlace被归一化到至少国家级+城镇,有时需要StateCode.我总是使用后者,我从来没有升级过.这意味着需要首先填充这些表.(e)这样的PK太广泛,不适合迁移到孩子身上,但不能放弃,因为它提供**行唯一性**.因此,使PK成为AK,并为PK创造代理.过宽的PK是代理人唯一有效的理由.如果你想要更多细节,请问一个新问题,我会回答. (2认同)
  • @Hamster_NL.我在答案中添加了一个小数据模型,并为Person提供了完整的quid. (2认同)
  • 如果您预计名称会经常更改,则可能需要使用自动增量 PK,这样您就不需要调整可能嵌入到所有数据的许多位置的值。另外,任意大写也非常烦人! (2认同)
  • 我知道这是一个老帖子,但你是否认真建议使用人名作为主键?!?一个:它不是唯一的,很多人都有相同的名字(有些甚至会有相同的DOB).还有两个:它不是一成不变的.人们可以改变他们的名字,所以也应该能够在软件中. (2认同)
  • @HackSlash。1) SQLite 不是 ANSI SQL。2)每个SQL和NON-sql平台都有不同的语法。3) 当给出示例 SQL 代码时,开发人员明白它只是一个示例,它不可能在每个平台上工作,他们必须插入其特定平台的详细信息。4) 如果您需要帮助,请提出新问题。 (2认同)
  • 我知道这是一篇旧帖子,但想问:鉴于有很多[程序员相信关于名称的谎言](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers- believe-about-名称/),我们如何处理没有“ID”就根本无法识别唯一性的情况?换句话说,两个人可能有相同的名字*和*出生日期,但仍然是不同的人。我们可能不被允许收集进一步的识别信息。我们获得唯一性的唯一方法是信任数据输入者。 (2认同)
  • @Charlieface 1)是的,有,但这种情况很少见。是的,需要更多识别信息。重点是出于上述所有原因,**不要**使用“任何 ID”作为“RecordId”。这并不意味着永远不要使用它:左下角链接的[数据模型](https://www.softwaregems.com.au/Documents/Student%20Resolutions/Ahmet%20Ertan%20DM.pdf)定义了一个。我的 [IDEF1X 简介](https://www.softwaregems.com.au/Documents/Documentary%20Examples/IDEF1X%20Introduction.pdf) 进一步解释了它。 (2认同)
  • 2)性能考虑。这绝不应该限制逻辑 [DM] 设计。所有正版 SQL 平台都没有复合 Key 的问题;宽键;永远不要在 Key 中使用 `varAnything`,这在任何平台上都是愚蠢的。始终在键中使用固定宽度。3) `DATETIME` 数据类型在 SQL 平台上具有微秒分辨率。在伪装者上,添加“序列”列。4) *唯一的信息根本不存在* *关系模型**需要唯一的行。所以制作一个柱子。5) 您没有意识到任何形式的“ID”列**不能**唯一化一行。 (2认同)
  • @Maggyero 0) `Person` 在链接数据模型中是完全清晰的。1) 关系键赋予行意义。是的,1::1 2) Key 需要稳定,而不是一成不变。宇宙中的一切都是可变的,应对它(莎莉·布朗嫁给了弗雷德·史密斯,并成为莎莉·史密斯*从那一刻起*)。不变性是一个毫无意义的标准,它唯一的价值是人为地提升“RecordIDs”。 (2认同)
  • @Maggyero 1) `(ArtistName, Birthdate)` 或 `(CountryCode, ArtistName)` 2) 因为它是教科书示例,并非旨在呈现现实。是的,当您从教科书转向现实时,您将添加许多表格。这完全没有说明教科书上的例子。 (2认同)