【问题标题】:Last inserted id from specific table从特定表中最后插入的 id
【发布时间】:2012-08-20 23:04:31
【问题描述】:
SELECT LAST_INSERT_ID() as id FROM table1

为什么这个查询有时会返回除 table1 之外的另一个表的最后插入的 id? 我在 Node.js(db-mysql 插件)中调用它,我只能做查询。

【问题讨论】:

    标签: mysql


    【解决方案1】:

    LAST_INSERT_ID() 只能告诉您最近自动生成的IDID 整个数据库连接,而不是每个单独的表,这也是为什么查询应该只读取SELECT LAST_INSERT_ID() - 不指定表格。
    一旦您在该连接上启动另一个 INSERT 查询,它就会被覆盖。如果您希望在插入某个表时生成ID,您必须在执行此操作后立即运行SELECT LAST_INSERT_ID()(或使用一些为您执行此操作的API 函数)。

    如果您想要当前在任意表中的最新ID,您必须在该表上执行SELECT MAX(id),其中id 是您的ID 列的名称。但是,这不一定是最近生成的ID,以防该行已被删除,也不一定是从您的连接生成的,以防另一个连接设法在您自己的INSERT 和您选择的ID

    (作为记录,您的查询实际上返回 N 行,其中包含该数据库连接上最近生成的 ID,其中 N 是 table1 中的行数。)

    【讨论】:

    • 我听说当插入行太多时 MAX(id) 不能很好地工作。然后我们有重复。
    • @KamilKrzyszczuk:正确,这就是为什么您不对刚刚生成的 ID 执行此操作的原因。当我说“在任意表中”时,这意味着“与您刚刚在此连接中插入的表不同的某个表”。如果您需要在多个表中生成 ID 并在后续使用它们,则必须在每次 INSERT 后选择它们(使用SELECT LAST_INSERT_ID())。
    • 我愿意,但在两个查询中。我可以在一个查询中执行 INSERT 和 SELECT last_insert_id() 吗?
    • @Kamil:您可以一次发送多个查询(如果您的数据库 API 允许),但这不是必需的,只要它是相同的连接,并且你没有做一些时髦的事情,比如同时为两个不同的请求使用同一个连接(你应该知道你是否这样做)。
    • 那么现在,我必须做这样的事情吗? "INSERT INTO table1(test) VALUES('test'); SELECT LAST_INSERT_ID()" 然后最后一个插入 id 将来自 table1?
    【解决方案2】:

    SELECT id FROM tableName ORDER BY id DESC LIMIT 1

    【讨论】:

    • 虽然您的回答似乎提供了实现用户想要的正确方法,但对他的问题的简短引用会很好......
    • 如果之前的某些插入失败,将无法工作。之前ID会自动递增。
    【解决方案3】:

    我通常选择自动递增的 ID 字段,按字段降序排列并将结果限制为 1。例如,在 wordpress 数据库中,我可以通过以下操作获取 wp_options 表的最后一个 ID:

    SELECT option_id FROM wp_options ORDER BY option_id DESC LIMIT 1;
    

    希望对您有所帮助。

    编辑 - 锁定表以避免更新表可能会导致返回不正确的 ID 可能是有意义的。

    LOCK TABLES wp_options READ;
    SELECT option_id FROM wp_options ORDER BY option_id DESC LIMIT 1;
    

    【讨论】:

    • 如果另一个插入发生在事务之外,这将是不正确的并给出错误的 ID。单个Transaction,多个语句,用last_insert_id()会保证结果是真实插入的id。
    • @ShellNinja - 如果在事务之外的另一个表中发生另一个插入,last_insert_id() 会给你错误的结果。选择当前表的最后一个 ID,在查询时使用可能的 LOCK 可能是最可靠的。锁定表 wp_options 读取; SELECT option_id FROM wp_options ORDER BY option_id DESC LIMIT 1;
    【解决方案4】:

    试试这个。这是有效的

    select (auto_increment-1) as lastId
    from information_schema.tables
    where table_name = 'tableName'
    and table_schema = 'dbName'
    

    【讨论】:

    • 这太危险了,因为它是全局表。您可能会在其他进程中获得由其他插入语句引起的 last id。
    【解决方案5】:

    如果我知道我永远不会关心生成的 id,我只会在 MySQL 中使用 auto_increment 或在 SQL Server 中使用 identity(1,1)

    select last_insert_id() 是简单的出路,但很危险。

    处理相关 id 的一种方法是将它们存储在 util 表中,例如:

    create table correlatives(
        last_correlative_used int not null, 
        table_identifier varchar(5) not null unique
    );
    

    你也可以创建一个存储过程来生成并返回X表的下一个id

    drop procedure if exists next_correlative;
    DELIMITER //
    create procedure next_correlative(
        in in_table_identifier varchar(5)
    )
    BEGIN
        declare next_correlative int default 1;
    
        select last_correlative_used+1 into next_correlative from correlatives where table_identifier = in_table_identifier;
    
        update correlatives set last_correlative_used = next_correlative where table_identifier = in_table_identifier;
    
        select next_correlative from dual;
    END //
    DELIMITER ;
    

    使用它

    call next_correlative('SALES');
    

    这允许您在插入记录之前保留 ID。有时您希望在完成插入之前在表单中显示下一个 id,并有助于将其与其他调用隔离开来。

    这是一个测试脚本:

    create database testids;
    
    use testids;
    
    create table correlatives(
        last_correlative_used int not null, 
        table_identifier varchar(5) not null unique
    );
    
    insert into correlatives values(1, 'SALES');
    
    drop procedure if exists next_correlative;
    DELIMITER //
    create procedure next_correlative(
        in in_table_identifier varchar(5)
    )
    BEGIN
        declare next_correlative int default 1;
        select last_correlative_used+1 into next_correlative  from correlatives where table_identifier = in_table_identifier;
        update correlatives set last_correlative_used = next_correlative where table_identifier = in_table_identifier;
        select next_correlative from dual;
    END //
    DELIMITER ;
    
    call next_correlative('SALES');
    

    【讨论】:

      【解决方案6】:

      如果您想使用这些解决方法:

      • SELECT id FROM tableName ORDER BY id DESC LIMIT 1
      • 从表名中选择 MAX(id)

      建议在插入行后使用 where 子句。如果没有这个,您将遇到不一致问题

      【讨论】:

      • 假设id 是数字并随时间增加。如果 ID 是例如 UUID 或随机选取,它将中断。
      【解决方案7】:

      最简单的方法: 从表名中选择 max(id);

      【讨论】:

        【解决方案8】:

        在我的表中 inv_id 是自动递增的

        为了我的目的,这是可行的

        select `inv_id` from `tbl_invoice`ORDER BY `inv_id` DESC LIMIT 1;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-18
          • 2011-11-06
          • 2011-03-06
          • 1970-01-01
          • 2013-11-13
          • 1970-01-01
          相关资源
          最近更新 更多