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

时间:2015-04-14 23:31:58

标签: mysql sql relational-database auto-increment

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

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

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

有没有办法可以在不丢失自动增量功能的情况下创建关系表?

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

提前致谢。

1 个答案:

答案 0 :(得分:15)

概念

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

  

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

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

ID字段不能是英语或技术或关系意义上的主键。

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

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

关系表必须具有唯一性

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

执行this code(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

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

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

就数据而言(实际数据减去无关的添加),数据name_lastname_first可以在没有ID字段的情况下存在。一个人的名字和姓氏没有在他们的额头上印上身份证。

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

纠正措施

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

  1. 您需要了解密钥

    • 由于我们已经从1970年代的ISAM文件发展到关系模型,因此您需要了解关系密钥。也就是说,如果您希望获得关系数据库的好处(完整性,功能,速度)。
    E F Coo​​d博士在他的 RM 中声明:

      

    密钥由数据

    组成

      

    表格中的行必须是唯一的

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

  2. Try this code声明对数据的唯一约束:

         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
    

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

  3. 第二级。思考那些超越修复的人 - 它。由于我们现在有行唯一性,天堂的名字是ID字段的目的,为什么我们甚至拥有它?哦,因为奇瓦瓦被命名为Rotty,我们不敢触摸它。

    它是PRIMARY KEY的声明是错误的,但它仍然存在,导致混淆和错误的期望。唯一真正的密钥是(name_last, name_fist),,此时它是备用密钥

    因此ID字段完全是多余的;支持它的索引也是如此;愚蠢的AUTOINCREMENT也是如此;虚假声明是PRIMARY KEY;你对它的任何期望都是错误的。

    因此请删除多余的ID字段。 Try this code

        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
    

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

    请记住这一点,并且每次都做得正确。

  4. 假教师

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

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

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

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

    答案

    现在剩下的问题了。

      

    有没有办法可以在不丢失自动增量功能的情况下创建关系表?

    这是一个自相矛盾的句子。我相信你会理解我的解释,关系表不需要 AUTOINCREMENT" features&#34 ;;如果文件有AUTOINCREMENT,则它不是关系表。

    AUTOINCREMENT仅适用于一件事:当且仅当您想要在SQL数据库容器中创建Excel电子表格时,请使用名为A, B,和{的字段在顶部{1}},并在左侧记录数字。在数据库术语中,这是SELECT的结果,数据的展平视图,数据的,这是有组织的(规范化)。

      

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

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

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

    • 确保用户唯一且user_names是唯一的唯一方法是在其上声明C,约束

    • 并删除用户文件中的UNIQUEuser_id

    • id提升为user_name

    是的,因为第三张桌子的整个问题,而不是巧合,都会被消除。

    第三个表是关联表。唯一需要的密钥(主密钥)是两个父主密钥的组合。这确保了的唯一性,这些行由其密钥标识,而不是由PRIMARY KEY

    标识。

    我警告你,因为同样的老师"谁教你实现IDs.字段的错误,教导在关联表中实现ID字段的错误,就像普通表一样,它是多余的,没有用处,引入重复,并导致混乱。它是双重多余的,因为提供的两把钥匙已经存在,盯着我们。

    由于他们不理解 RM 或关系术语,因此他们会调用关联表" link"或"地图"表。如果他们有ID字段,则实际上是文件。

    查找表

    对于查找表或参考表,

    ID字段特别愚蠢的事情。它们中的大多数具有可识别的代码,因此不需要枚举其中的代码列表,因为代码(应该)是唯一的。

    此外,将子表中的代码作为FKs是一件好事:代码更有意义,它通常可以节省不必要的连接:

    ID

    而不是:

        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
    

    完整示例

    根据您问题中的详细信息,我怀疑您有SQL语法和FK定义问题,因此我将提供您需要的整个解决方案作为示例(因为您没有给出文件定义):

        CREATE TABLE gender (
            gender_code  CHAR(2)  NOT NULL,
            name         CHAR(30) NOT NULL
    
            CONSTRAINT PK 
                PRIMARY KEY ( gender_code )
    
            CONSTRAINT AK 
                UNIQUE ( name )
            )
    

    在那里, 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;没有额外的指数;没有重复的;没有错误的期望;没有相应的问题。

    数据模型

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

    • Example User Sport Data Model

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

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

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