【问题标题】:MySQL auto-increment between tablesMySQL表之间的自动增量
【发布时间】:2012-07-27 01:21:45
【问题描述】:

在 MySQL 中,是否可以在两个不同的表中拥有一个自动递增的列?示例:table1 有一个“secondaryid”列,table2 也有一个“secondaryid”列。是否可以让 table1.secondaryid 和 table2.secondaryid 保存相同的信息?像 table1.secondaryid 可以保存值 1、2、4、6、7、8 等,而 table2.secondaryid 可以保存值 3、5、9、10?这样做的原因有两个:1)这两个表将在单独的“喜欢”表中引用(类似于用户在 facebook 上喜欢一个页面)和 2)table2 中的数据是 table1 使用主键的子集。因此,table2 中包含的信息取决于 table1,因为它们是不同类别的主题。 (类别为 table1,主题为 table2)。是否可以执行上述操作,或者是否有其他一些我不知道的结构性工作?

【问题讨论】:

    标签: php mysql sql


    【解决方案1】:

    您似乎想在两个单独的表格中区分类别和主题,但在另一个表格 likes 中引用它们的 ID 以方便用户喜欢类别或主题。

    您可以做的是创建一个具有子类型categoriestopics 的超实体表。自动递增的键将在超实体表中生成,并仅插入到两个子类型表中的一个中(取决于它是类别还是主题)。

    子类型表通过 1:1 关系中的自动递增字段引用此超实体。

    这样,您可以简单地将超实体表链接到likes 表,仅基于一列(可以表示类别或主题),并且不会出现子类型表中的id两者都有。

    以下是一个简化示例,说明如何对此进行建模:

    此模型允许您维护类别和主题之间的关系,但在 superentity 表中概括了这两个实体。

    此模型的另一个优点是您可以将子类型表中的公共字段抽象到超实体表中。例如,categoriestopics 都包含字段 titleurl:您可以将这些字段放在 superentity 表中,因为它们是其子类型的公共属性。仅将特定于子类型表的字段放入子类型表中。

    【讨论】:

    • 那么 superentity 将类别和主题的值保存在一张表中?
    • @ryno 是的,只有公共属性。超实体将在其id 字段中保存两个表的自动递增键,但子类型表仅引用超实体表中属于其类型的键。例如,在超实体表中,您将拥有ids 1,2,3,4,5,6,7,8,9。如果2,5,6,7 是类别,1,3,4,8,9 是主题...类别表将仅引用2,5,6,7,主题表将引用1,3,4,8,9
    • 那么两个 id 是否都在 superentity 表的同一列中?
    • @ryno,是的,并且子类型仅引用超级实体表的特定 ids。 superentity 表中id 的值可以表示类别或主题,但有关类别和主题的实际信息存储在它们各自的子类型表中。
    • 你有什么资源可以指点我作为构建这个结构的参考吗?或者更深入地解释一下,因为我还没有使用这种 db 结构的方法(而且我对 php 和 sql 比较陌生)?
    【解决方案2】:

    您不能在表之间共享 auto_increment 值,但您可以让它看起来是:

    set @@auto_increment_increment=2; // change autoinrement to increase by 2
    
    create table evens (
        id int auto_increment primary key
    );
    alter table evens auto_increment = 0;
    
    create table odds (
        id int auto_increment primary key
    );
    alter table odds auto_increment = 1;
    

    这样做的缺点是您正在更改全局设置,因此 ALL auto_inc 字段现在将增长 2 而不是 1。

    【讨论】:

    • 聪明的解决方法,但是,在同一个数据库中的其他表中需要一个自动增量,增加一。不过谢谢
    【解决方案3】:

    如果您只是希望两个表中的 ID 不同,您可以最初将 table2 的 AUTO_INCREMENT 设置为某个大数字。

    ALTER TABLE `table2` AUTO_INCREMENT=1000000000;
    

    【讨论】:

    • 通过具有INT 主键的逻辑是变相的Y2K。
    • 不是,但至少 int 溢出是一个已知数量。像 1000000000 这样的任意幻数更糟糕。
    • 是的,但没有什么能阻止您使用已知的幻数(例如 2147483647)。
    【解决方案4】:

    听起来你想要一个 MySQL 等价的序列,它可以在 DBMS 中找到,比如 PosgreSQL。有一些已知的方法,其中大部分涉及创建跟踪序列名称的表和保持当前值的整数字段。这种方法允许您查询包含该序列的表,并在必要时将其用于一个或多个表。

    There's a post here 在这个问题上有一个有趣的方法。我还在 DB PEAR module 中看到了这种方法,现在已经过时了。

    【讨论】:

      【解决方案5】:

      您需要通过客户端或在mysql内部通过sql函数手动设置另一个表的增量值:

      ALTER TABLE users AUTO_INCREMENT = 3
      

      所以在插入 table1 之后,你会取回最后一个自动增量,然后通过它修改另一个表的自动增量字段。

      【讨论】:

        【解决方案6】:

        我对你的问题感到困惑。如果表 2 是表 3 的子集,为什么要让它共享主键值。您的意思是表 2 和表 3 之间的类别是分开的吗?

        如果是这样,我会质疑将它们放入单独表格的设计选择。听起来你有两种不同的情况之一。首先是你有一个“类别”实体,它有两种风格。在这种情况下,您应该有一个单独的类别表,可能带有一个指定类别类型的类型列。

        第二个是您的用户可以“喜欢”不同的东西。在这种情况下,“用户喜欢”表应该为每个对象有一个单独的外键。您可以使用复合外键完成一个技巧,之后您将拥有对象的类型和常规的数字 id。因此,like 表将具有“type”和“id”。 person 表将有一列填充“PERSON”,另一列填充数字 id。连接会说“在 a.type = b.type 和 a.id = b.id 上”。 (或者“类型”上的部分可能是隐含的,在表的选择中)。

        【讨论】:

        • 抱歉问题令人困惑且解释不清,但是,您的第二个猜测是,用户可以“喜欢”不同类型的事物是正确的。他们可以喜欢一个名为“cats”的类别或一个名为“somespeciesofcat”的主题,为了导航到“somespeciesofcat”,他们需要通过“cats”。所以你的答案似乎是在正确的轨道上。能再解释一下吗?
        • 实际上,您可能应该将所有类别放在一个表中,并带有一个用于自联接的父类别。在类别表中,您可以有一列给出类别的深度,如果需要,还可以提供父类别。如果属性完全不同,您只会使用不同的表——例如,我可以喜欢国家,也可以喜欢同事。
        • 所以 likes 表会有一个用户 ID 列,以及网站上每个主题和类别的列?那么如果有 50 个主题和 100 个类别,那么 like 表将有 151 列(50+100+1)? h
        • 不,不,不。类别表将有一个类型,因此它会有一个包含“主题”列和“类别”列的列,然后是适当的描述性列。一个查找表,许多不同的东西。或者,一个类别和主题的表格,但有自己的、独立的主键。
        • 我明白你在说什么,但是,这不适用于我访问每个页面的方法的当前设置,因为有一个 category.php 页面和一个 topic.php 页面调用每个页面分别通过获取网址,如果它们在同一张桌子上,我无法完成这项工作。
        【解决方案7】:

        你可以用触发器来做到这一点:

        -- see http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
        CREATE TABLE sequence (id INT NOT NULL);
        INSERT INTO sequence VALUES (0);
        
        CREATE TABLE table1 (
            id INT UNSIGNED NOT NULL AUTO_INCREMENT,
            secondardid INT UNSIGNED NOT NULL DEFAULT 0,
            PRIMARY KEY (id)
        );
        
        CREATE TABLE table2 (
            id INT UNSIGNED NOT NULL AUTO_INCREMENT,
            secondardid INT UNSIGNED NOT NULL DEFAULT 0,
            PRIMARY KEY (id)
        );
        
        DROP TRIGGER IF EXISTS table1_before_insert;
        DROP TRIGGER IF EXISTS table2_before_insert;
        
        DELIMITER //
        
        CREATE
        TRIGGER table1_before_insert
            BEFORE INSERT ON 
                table1
            FOR EACH ROW
        BEGIN
            UPDATE sequence SET id=LAST_INSERT_ID(id+1);
            NEW.secondardid = LAST_INSERT_ID();
        END;
        //
        
        CREATE
        TRIGGER table2_before_insert
            BEFORE INSERT ON 
                table2
            FOR EACH ROW
        BEGIN
            UPDATE sequence SET id=LAST_INSERT_ID(id+1);
            NEW.secondardid = LAST_INSERT_ID();
        END;
        //
        

        【讨论】:

          猜你喜欢
          • 2015-02-03
          • 1970-01-01
          • 2011-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-15
          • 1970-01-01
          相关资源
          最近更新 更多