【问题标题】:MySQL ON DUPLICATE KEY - last insert id?MySQL ON DUPLICATE KEY - 最后插入ID?
【发布时间】:2010-10-21 04:22:11
【问题描述】:

我有以下疑问:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE a=1

我想要插入或更新的 ID。通常我会运行第二个查询以获得此信息,因为我相信 insert_id() 仅返回“插入”ID 而不是更新后的 ID。

有没有办法在不运行两个查询的情况下插入/更新并检索行的 ID?

【问题讨论】:

  • 与其假设,不如自己测试一下?上面编辑中的 SQL 确实有效,并且通过我的测试,比使用 INSERT IGNORE 或选择先查看是否有重复发现插入失败要快。
  • 警告:建议的解决方案有效,但即使没有插入,auto_increment 值也会继续增加。如果重复键经常出现,您可能需要在上述查询之后运行alter table tablename AUTO_INCREMENT = 0;,以避免您的 id 值出现大的差距。
  • @FrankForte 你在开玩笑说alter table 在运行时,在生产中,有并发用户,对吧?

标签: mysql insert-id


【解决方案1】:

确切地说,如果这是原始查询:

INSERT INTO table (a) VALUES (0)
 ON DUPLICATE KEY UPDATE a=1

'id' 是自动递增的主键,而不是这是可行的解决方案:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1

都在这里:http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

如果一个表包含一个 AUTO_INCREMENT 列和 INSERT ... UPDATE 插入一行,LAST_INSERT_ID() 函数返回 AUTO_INCREMENT 值。如果该语句改为更新一行, LAST_INSERT_ID() 没有意义。但是,您可以解决此问题 通过使用 LAST_INSERT_ID(expr)。假设 id 是 AUTO_INCREMENT 列。

【讨论】:

  • 是的,请参阅您所说的相同答案。无需恢复 3 年前的帖子。无论如何,感谢您的努力。
  • @tombom 我发布此答案的唯一原因是因为接受的答案不正确 - 如果没有什么可更新的,它将无法工作。
【解决方案2】:

我遇到了一个问题,当 ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id) 将主键递增 1。所以会话中下一个输入的 id 将递增 2

【讨论】:

    【解决方案3】:

    查看此页面:https://web.archive.org/web/20150329004325/https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
    在页面底部,他们解释了如何通过将表达式传递给 MySQL 函数来使 LAST_INSERT_ID 对更新有意义。

    来自 MySQL 文档示例:

    如果表包含 AUTO_INCREMENT 列并且 INSERT ... UPDATE 插入一行,LAST_INSERT_ID() 函数将返回 AUTO_INCREMENT 值。如果该语句改为更新一行,则 LAST_INSERT_ID() 没有意义。但是,您可以使用 LAST_INSERT_ID(expr) 解决此问题。假设 id 是 AUTO_INCREMENT 列。要使 LAST_INSERT_ID() 对更新有意义,请按如下方式插入行:

    INSERT INTO table (a,b,c) VALUES (1,2,3)
      ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
    

    【讨论】:

    • 在查看该页面时不知何故我错过了这一点。所以更新部分显示为: UPDATE id=LAST_INSERT_ID(id) 这很好用。谢谢!
    • 据说php函数mysql_insert_id()在两种情况下都返回正确的值:php.net/manual/en/function.mysql-insert-id.php#59718
    • @PetrPeller - 好吧,不看 MySQL 内部,这可能意味着它会产生一个值,但该值与您刚刚运行的查询无关。换句话说,一个调试起来很痛苦的问题。
    • 在 5.1.12 之后这应该不再需要了,但是我今天发现了一个例外。如果您有一个自动增量 pk,并且在电子邮件地址上有一个唯一键,并且基于电子邮件地址的“重复更新”触发器,请注意 last_insert_id 不会是更新行的自动增量值。它似乎是最近插入的自动增量值。这有很大的不同。解决方法与此处显示的相同,即在更新查询中使用 id=LAST_INSERT_ID(id)。
    • 现在引用的部分已经改变,the Docs:If a table contains an AUTO_INCREMENT column and INSERT ... ON DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID() function returns the AUTO_INCREMENT value.
    【解决方案4】:

    如果您使用自动增量,现有的解决方案就可以工作。我有一种情况,用户可以定义一个前缀,它应该在 3000 处重新启动序列。由于这个不同的前缀,我不能使用自动增量,这使得 last_insert_id 为空插入。我用以下方法解决了它:

    INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1);
    SELECT LAST_INSERT_ID();
    

    如果前缀存在,它将增加它并填充 last_insert_id。 如果前缀不存在,它将插入值为 3000 的前缀,并使用 3000 填充 last_insert_id。

    【讨论】:

      【解决方案5】:

      值得注意的是,这可能很明显(但为了清楚起见,我还是会这么说),REPLACE 会在插入新数据之前清除现有的匹配行。 ON DUPLICATE KEY UPDATE 只会更新您指定的列并保留该行。

      来自manual

      REPLACE 的工作方式与 INSERT 完全相同, 除了如果表中的旧行 具有与 a 的新行相同的值 PRIMARY KEY 或 UNIQUE 索引,旧的 行在新行被删除之前被删除 插入。

      【讨论】:

        【解决方案6】:

        我不知道你的 MySQL 版本是什么,但使用 InnoDB,autoinc 存在错误

        5.1.20 中的错误并在 5.1.23 中更正 http://bugs.mysql.com/bug.php?id=27405

        5.1.31 中的错误并在 5.1.33 中更正 http://bugs.mysql.com/bug.php?id=42714

        【讨论】:

          【解决方案7】:

          您可能会查看 REPLACE,如果记录存在,它本质上是删除/插入。但这会更改自动增量字段(如果存在),这可能会破坏与其他数据的关系。

          【讨论】:

          • 啊,是的 - 我正在寻找不会删除以前 ID 的东西
          • 这也可能很危险,因为这也可能导致删除另一个相关数据(通过约束)。
          猜你喜欢
          • 2018-05-01
          • 2011-04-22
          • 2018-05-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多