【问题标题】:MySQL auto generate following numberMySQL自动生成以下号码
【发布时间】:2012-08-30 16:56:50
【问题描述】:

我的关系表中有 4 列:

  1. 身份证
  2. CID - 课程编号
  3. LID - 相关课程唯一 ID
  4. course_based_id - 解释如下

在另一个名为lessonscourses 的表中有许多具有唯一ID 的课程和课程。这个表就是它们之间的关联表。基本上,它将唯一的课程 ID 分配给唯一的课程 ID。但是.. 需要基于课程的课程 ID。我的意思是,例如让我们看一下屏幕截图中的第一行和第二行

盖子 1 是课程 2 的第一课,盖子 3 是课程 2 的第二课......以此类推。所以如果我插入 cid 2, lid 128 它必须是第三课当然 2。

现在,问题是,我想在插入时自动生成这个数字:

$q="INSERT INTO `courses-lessons` (`cid`, `lid`) VALUES (?,?)";

但不知道该怎么做。一些MySQL功能?还是查询里面的东西?

【问题讨论】:

    标签: php mysql sql


    【解决方案1】:

    如果您使用 MyISAM 引擎来存储此表,这可以相对简单地完成:您只需这样定义字段:

    cid INT NOT NULL,
    course_based_id INT NOT NULL AUTO_INCREMENT,
    ...
    PRIMARY KEY (cid, course_based_id)
    

    然后任何INSERT 将根据cid 自动为course_based_id 分配一个新的(+1) 值。这是一个 Fiddle 说明这个概念。

    你可以在MySQL documentation找到更多信息。

    不幸的是,InnoDB 引擎中没有这样的机制。所以也许你可以摆脱以下例程(这是一个伪代码,有一些细微差别):

    1) lock table for writing; 
    2) @x = SELECT MAX(course_based_id) WHERE cid = %cid_to_be_inserted%;
    3) INSERT (..., course_based_id) VALUES (..., @x + 1);
    4) unlock table;
    

    我建议检查this answer;它适用于 PostgreSQL,而不是 MySQL,但详细描述了一种可能的实现。

    更新:以下是实现该行为的一组实际查询示例:

    CREATE TABLE tx
      (id INT NOT NULL, cid INT NOT NULL, lid INT NOT NULL,
       course_based_id INT NOT NULL,
       PRIMARY KEY (id),
       UNIQUE KEY (cid, course_based_id)
    );
    
    LOCK TABLE tx WRITE, tx AS t READ;
    
    INSERT INTO tx (id, cid, lid, course_based_id)
      SELECT 2, 2, 1, 
             1 + COALESCE(
                   (SELECT MAX(course_based_id) 
                      FROM tx AS t 
                     WHERE cid = 2), 
                 0);
    
     INSERT INTO tx (id, cid, lid, course_based_id)
       SELECT 3, 2, 3, 
              1 + COALESCE(
                    (SELECT MAX(course_based_id) 
                      FROM tx AS t WHERE cid = 2),
                  0);
    
     UNLOCK TABLES;
    

    如您所见,没有直接计算下一个 course_based_id 值,但我们在这里得到了序列。

    【讨论】:

    • 表中有 1 个 auto_increment 列。我无法定义第二个。
    • 我可以将它的引擎从 INNODB 更改为 myisam 而不会丢失数据吗?顺便说一句,我也有与这张表相关的外键
    • 你在吗?为什么不回复我的cmets?
    • @epic_syntax:如果你需要外键,那么你就不能使用MyISAM,所以这个技巧是行不通的。
    • @ypercube 你有什么建议?
    【解决方案2】:

    如果你想要引用完整性(外键)你正在使用 InnoDB,所以(好的)MyISAM 技巧不起作用。

    您可以做的是在插入表格期间生成那些course_based_id

    编写一个 - 不那么复杂 - 执行插入并且不允许其他代码插入此表的过程 - 通过此过程除外。您还需要一个用于更新的过程(如果您介意在此 course_based_id 中有空白,则需要一个用于删除的过程)。

    所以,而不是:

    INSERT INTO courses_lessons 
      (cid, lid) 
    VALUES 
      ( ?cid, ?lid ) ;
    

    您将拥有,包含在存储过程中以捕获任何错误(重复等):

    INSERT INTO courses_lessons 
      (cid, lid, course_based_id) 
    SELECT 
      ?cid, ?lid, 
      1 + COALESCE( ( SELECT MAX(course_based_id) 
                      FROM courses_lessons 
                      WHERE cid = ?cid
                    ), 0)
    FROM
      dual ;
    

    对于此表,您实际上并不需要 id 列。 (cid, lid) 上的主键足以识别行。您还需要在(cid, course_based_id) 上添加一个唯一键:

    ALTER TABLE courses_lessons 
      ADD CONSTRAINT UQ_cid_course_based_id
        UNIQUE cid_course_based_id_UQ
          (cid, course_based_id) ;
    

    【讨论】:

    • 它不会受到竞争条件的影响吗?
    • 所以应该用锁表来完成,好的。我实际上已经考虑过在(cid,course_based_id)上创建一个触发器模拟序列。使用存储过程是另一个不错的选择。
    • 触发器有级联效果的问题,所以这可能不是一个选项。
    • add a unique key on (cid, course_based_id) 请写查询。我正在使用可视数据库管理器,但没有找到与英国相关的任何内容。
    • 我不这么认为。我认为在 InnoDB 中混合级联效果和触发器尚未修复。
    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 2010-10-04
    相关资源
    最近更新 更多