【问题标题】:MySQL Trigger: copy auto_increment value to another column upon insertMySQL 触发器:在插入时将 auto_increment 值复制到另一列
【发布时间】:2013-09-28 08:55:36
【问题描述】:

我需要在插入时将 auto_increment ID 值复制到另一列中。 我想我需要一个“插入后”触发器,否则新 ID 是未知的..?

我试过了:

IF NEW.content IS NULL THEN
    SET NEW.content = NEW.id;
END IF

但它抱怨:

触发器后不允许更新新行

【问题讨论】:

  • 你的桌子叫什么名字?
  • 表名是'notes'
  • CREATE TRIGGER insert_example BEFORE INSERT ON example FOR EACH ROW SET NEW.object_id = NEW.id;试试这个。
  • 无论如何将该列设置为自动递增的值有什么意义?如果它看到内容列为空并且您的问题消失了,您可以修改提取数据的查询以使用自动增量的值。
  • 主要是在'content'为空的时候搜索ID,这在SQL中也确实可以做到。也许这是更好的解决方案..

标签: mysql sql triggers


【解决方案1】:

关于此代码

  CREATE TRIGGER insert_example
  BEFORE INSERT ON notes
  FOR EACH ROW 
  SET NEW.content = (
        SELECT AUTO_INCREMENT 
        FROM information_schema.TABLES 
        WHERE TABLE_SCHEMA = DATABASE() 
        AND TABLE_NAME = 'notes'
  );

我做了这样的事情

SET NEW.content = (SELECT CONCAT('ID',LPAD(AUTO_INCREMENT, number,'0')) 
FROM information_schema.TABLES 
WHERE TABLE_SCHEMA = DATABASE() 
AND TABLE_NAME = 'notes');

如果您在 id 字段上使用 UNSIGNED_ZEROFILL...并且您可能需要自定义类型的“公共”id...

【讨论】:

    【解决方案2】:

    正如 OP 指出的那样,NEW.id 不适用于自动增量;可以使用以下触发器(使用风险自负)。试试这个。

    CREATE TRIGGER insert_example 
          BEFORE INSERT ON notes
          FOR EACH ROW 
          SET NEW.content = (
                SELECT AUTO_INCREMENT 
                FROM information_schema.TABLES 
                WHERE TABLE_SCHEMA = DATABASE() 
                AND TABLE_NAME = 'notes'
          );
    

    【讨论】:

    • 同样,我想到了一个 BEFORE INSERT 触发器,NEW.content = LAST_INSERT_ID() + 1 但我认为这也有风险..
    • 不保证下一个auto_increment值是LAST_INSERT_ID()+1。见autoinc_lock_mode for INNODB
    • 所以你从这个链接获得帮助并知道如何实施?
    【解决方案3】:

    如果您出于某种原因确实需要此行为,您可以通过使用单独的表进行排序和BEFORE INSERT 触发器来实现它

    首先,您需要一个用于排序目的的简单表格,如下所示

    CREATE TABLE table1_seq
    (
      id int not null auto_increment primary key
    );
    

    那么你的事实表架构可能看起来像

    CREATE TABLE table1
    (
      id int not null default 0 primary key,
      content int
    );
    

    现在触发

    DELIMITER $$
    CREATE TRIGGER tg_ai_table1
    BEFORE INSERT ON table1
    FOR EACH ROW
    BEGIN
      INSERT INTO table1_seq() VALUES();
      SET NEW.id = LAST_INSERT_ID(), NEW.content = COALESCE(NEW.content, NEW.id);
    END$$
    DELIMITER ;
    

    现在你如果你插入table1

    INSERT INTO table1 () VALUES (NULL),(-1);
    

    你会有

    |身份证 |内容 | |----|---------| | 1 | 1 | | 2 | -1 |

    这里是SQLFiddle演示

    【讨论】:

    • @kvdmolen 有帮助吗?您的问题需要更多帮助吗?
    • 答案是:不可能使用触发器。我更喜欢更简单的解决方法(请参阅初始问题中的评论),否则我必须在应用程序层中构建它。感谢您的帮助!
    【解决方案4】:

    是的,使用触发器是不可能的。您能做的最好的事情就是将INSERT 语句替换为CALL some_procedure(values...),并在其中实现上述逻辑。 (假设您可以在应用程序端更改 SQL)。

    另一种(但更丑陋的)设置事件的解决方案,它会定期修复您的记录,其中content=NULL

    【讨论】:

      【解决方案5】:

      有点麻烦,你能说吗

      DELIMITER $$
      CREATE TRIGGER sometrigger
      AFTER INSERT ON sometable
      BEGIN
        UPDATE sometable SET content = NEW.id WHERE id = NEW.id;
      END $$
      

      通过完整查询更新(相同)表,而不是尝试使用 SET。

      甚至

      DELIMITER $$
      CREATE TRIGGER sometrigger
      AFTER INSERT ON sometable
      BEGIN
        UPDATE sometable SET content = id WHERE content is null;
      END $$
      

      (这有点类似于 Allita 对事件的建议)

      【讨论】:

      • 它在 MySQL 中不起作用。您不能在定义了触发器的表上的触发器内执行任何 DML 语句。
      • 后者给出另一个错误:“无法更新存储函数/触发器中的表'notes',因为它已被调用此存储函数/触发器的语句使用。”
      • 对不起。我承认没试过。我已经使用触发器插入(另一个)新行,但没有尝试更新,只是假设它会起作用。我不能对自己的答案投反对票!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 2016-10-03
      • 1970-01-01
      • 2019-05-20
      • 2013-03-11
      • 2014-12-31
      • 2021-12-12
      相关资源
      最近更新 更多