Como obter o próximo ID de auto-incremento no mysql

114

Como obter o próximo id no mysql para inseri-lo na tabela

INSERT INTO payments (date, item, method, payment_code)
VALUES (NOW(), '1 Month', 'paypal', CONCAT("sahf4d2fdd45", id))
faressoft
fonte
1
usar uma auto_incrementcoluna
malha de
Você quer o próximo id, ou o id da linha que você está inserindo atualmente? Ou seja, o id no final do código de pagamento deve ser o id da linha em que o código de pagamento está armazenado?
Mike de
id da linha que estou inserindo
faressoft
6
Nesse caso, concatene os valores ao recuperá-los, não ao inseri-los. É muito mais fácil assim, e você descarta obter o id errado ou ter que executar uma atualização - pense no que aconteceria se a linha que você acabou de inserir for solicitada por outro cliente, antes que a atualização tenha chance de ser executada: o cliente acabaria com um código de pagamento inválido. Em um sistema de baixo tráfego, isso pode não ocorrer, mas não vejo sentido em correr o risco.
Mike de
... ou como @binaryLV aponta, o bloqueio de recursos também pode resolver o problema. Consulte: dev.mysql.com/doc/refman/5.5/en/lock-tables.html
Mike

Respostas:

12

Use LAST_INSERT_ID()da sua consulta SQL.

Ou

Você também pode usar mysql_insert_id()para obtê-lo usando PHP.

Sarfraz
fonte
13
@Sarfraz: A pergunta era sobre a PRÓXIMA id, não a ÚLTIMA como você mencionou LAST_INSERT_ID().
Felipe Pereira
1
Se as linhas forem excluídas da tabela, o máximo estará errado
peterchaula
apenas uma nota de '17 - mysql * funções estão obsoletos - acima pode ser feito commysqli_insert_id
treyBake
quem marcou isso como resposta? a questão é sobre o próximo ID de inserção, não o último.
Amit Shah
253

Você pode usar

SELECT AUTO_INCREMENT
FROM information_schema.tables
WHERE table_name = 'table_name'
AND table_schema = DATABASE( ) ;

ou se você não deseja usar information_schema você pode usar este

SHOW TABLE STATUS LIKE 'table_name'
Ravi404
fonte
Obrigado pelas duas primeiras opções .. Mas a terceira é apenas o número dois chamado de PHP .. Não tenho certeza o que torna isso mais rápido em grandes bancos de dados ...
Gerard ONeill
1
@GerardONeill Removido
ravi404 de
3
porque um cache é usado para recuperar os dados de information_schema.tables, esta solução não funciona mais para o mysql 8.
Bruno
1
@Bruno você pode postar uma referência?
mvorisek
1
Este documento oficial TABLES.AUTO_INCREMENTestá armazenado em dev.mysql.com/doc/refman/8.0/en/… . O blog do Mysql também tem várias postagens sobre isso, mas o sistema variável que eles mencionam parece desatualizado: mysqlserverteam.com/… mysqlserverteam.com/…
Bruno
50

Você pode obter o próximo valor de incremento automático fazendo:

SHOW TABLE STATUS FROM tablename LIKE Auto_increment
/*or*/
SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'tablename'

Observe que você não deve usar isso para alterar a tabela, use uma coluna auto_increment para fazer isso automaticamente.
O problema é que last_insert_id()é retrospectivo e, portanto, pode ser garantido dentro da conexão atual.
Este bebê é prospectivo e, portanto, não é o único por conexão e não é confiável.
Isso funcionaria apenas em um único banco de dados de conexão, mas os bancos de dados de conexão única hoje têm o hábito de se tornarem bancos de dados de várias conexões amanhã.

Vejo: SHOW TABLE STATUS

João
fonte
5
Eu não votei contra ele, mas o problema de tentar usar o último valor de incremento automático é que ele pode não ser o último quando você começar a usá-lo - não importa a rapidez com que SELECT e o INSERT subsequente sejam realizados.
Mike de
@ Mike, e se for feito em uma única consulta? Algo assim insert into table_name (field1, field2) select 'constant', auto_increment from information_schema.tables where table_name = 'table_name'? Eu usaria a atualização no after insertgatilho e last_insert_id(), embora ...
binaryLV
1
@binaryLV: Quanto menor for a lacuna entre SELECT e INSERT, menor será a chance de que o valor tenha mudado, mas isso não exclui completamente. Imagine um sistema com milhares de acessos por minuto no banco de dados - as chances de o valor ter mudado aumentam drasticamente. O bloqueio de tabela ou linha pode impedir isso se for feito como uma única consulta, mas isso depende de um comportamento específico do mecanismo de banco de dados que pode não estar bem documentado. Eu iria com uma próxima UPDATEse eu também tivesse. Mas prefiro apenas concatenar os dois no momento da exibição e evitar todo o trabalho.
Mike de
3
SHOW TABLE STATUSespera ver database namedepois FROMe 'table name pattern'depois LIKE.
x-yuri
2
porque um cache é usado para recuperar os dados de information_schema.tables, esta solução não funciona mais para o mysql 8.
Bruno
15

Isso retornará o valor de incremento automático para o banco de dados MySQL e não verifiquei com outros bancos de dados. Observe que se você estiver usando qualquer outro banco de dados, a sintaxe da consulta pode ser diferente.

SELECT AUTO_INCREMENT 
FROM information_schema.tables
WHERE table_name = 'your_table_name'
     and table_schema = 'your_database_name';

SELECT AUTO_INCREMENT 
FROM information_schema.tables
WHERE table_name = 'your_table_name'
     and table_schema = database();
Chaminda Bandara
fonte
SELECT AUTO_INCREMENT FROM information_schema.tables WHERE table_name = 'your_table_name' e table_schema = 'your_database_name';
LJay
10

A resposta principal usa PHP MySQL_ para uma solução, pensei em compartilhar uma solução PHP MySQLi_ atualizada para conseguir isso. Não há saída de erro neste exemplo!

$db = new mysqli('localhost', 'user', 'pass', 'database');
$sql = "SHOW TABLE STATUS LIKE 'table'";
$result=$db->query($sql);
$row = $result->fetch_assoc();

echo $row['Auto_increment'];

Expulsa o próximo incremento automático que surge em uma tabela.

Hexchaimen
fonte
porque um cache é usado para recuperar os dados de information_schema.tables, esta solução não funciona mais para o mysql 8.
Bruno
9

Em PHP, você pode tentar isso:

$query = mysql_query("SELECT MAX(id) FROM `your_table_name`");
$results = mysql_fetch_array($query);
$cur_auto_id = $results['MAX(id)'] + 1;

OU

$result = mysql_query("SHOW TABLE STATUS WHERE `Name` = 'your_table_name'");
$data = mysql_fetch_assoc($result);
$next_increment = $data['Auto_increment'];
Naresh Jain
fonte
5
Tenha em mente que, com o primeiro método, se o registro com o id mais alto for eliminado, você criará um novo registro com o id que o id eliminado costumava ter.
Tom Jenkinson
e se a chave anterior foi usada em outras tabelas e ainda está lá, você pode acabar com uma magia muito estranha
Tebe
o primeiro retorna um id errado se você descartar o último registro inserido,
Ali Parsa
6

Solução:

CREATE TRIGGER `IdTrigger` BEFORE INSERT ON `payments`
  FOR EACH ROW
BEGIN

SELECT  AUTO_INCREMENT Into @xId
    FROM information_schema.tables
    WHERE 
    Table_SCHEMA ="DataBaseName" AND
    table_name = "payments";

SET NEW.`payment_code` = CONCAT("sahf4d2fdd45",@xId);

END;

"DataBaseName" é o nome da nossa base de dados

Anjo
fonte
5

Uma consulta simples faria SHOW TABLE STATUS LIKE 'table_name'

Raa
fonte
4

Você pode usar o gatilho mysql

Nick Pavluk
fonte
Atualizar payment_codeno after insertgatilho parece ser a melhor opção.
binaryLV de
3

Você não pode usar o ID durante a inserção, nem precisa dele. O MySQL nem sabe o ID quando você está inserindo esse registro. Você poderia apenas salvar "sahf4d2fdd45"na payment_codetabela e usar ide payment_codedepois.

Se você realmente precisa que seu código_de_pagamento tenha o ID nele, ATUALIZE a linha após a inserção para adicionar o ID.

Jacob
fonte
+1 Para tornar isso um pouco mais explícito: se você pegar o valor 'mais recente' de uma coluna, só é garantido que será o valor mais recente no momento exato em que você o pegar. Pode não ser o valor mais recente quando você vier a usar esse valor em uma inserção subsequente. No caso de uma coluna de incremento automático, sempre há a chance de que outro valor tenha sido adicionado entre o momento em que você recuperou o id e o momento em que o inseriu em outro lugar. Se você está referenciando uma linha que acabou de inserir, usar LAST_INSERT_ID () é adequado. Se você está tentando garantir um valor exclusivo, não é.
Mike de
@cularis, o MySQL sabe o próximo id auto_increment, ele está listado na information_schema.tablestabela.
Johan
1
@faressoft: Se a ideia é ter um código de pagamento que compreende uma única string mais o id da linha que contém esse código de pagamento, basta combinar os dois quando você recuperar a linha - com um SELECT ... CONCAT(payment_code, id)ou no código do seu aplicativo. Você pode até envolver o SELECTem a VIEW, de forma que sempre retorne o valor correto, sem se preocupar com o CONCAT em cada SELECT do seu aplicativo.
Mike de
3

Para que você precisa do próximo ID incremental?

O MySQL permite apenas um campo de incremento automático por tabela e também deve ser a chave primária para garantir a exclusividade.

Observe que quando você obtém o próximo ID de inserção, ele pode não estar disponível ao usá-lo, pois o valor que você possui está apenas no escopo dessa transação. Portanto, dependendo da carga em seu banco de dados, esse valor já pode ser usado no momento em que a próxima solicitação chegar.

Eu sugeriria que você revise seu projeto para garantir que não precise saber qual valor de incremento automático atribuir a seguir

Stephen Senkomago Musoke
fonte
Não é uma boa ideia presumir o tipo de aplicativo que requer o ID. Existem aplicativos como o que estou trabalhando no momento que precisam do próximo ID incremental e o valor recuperado não corre o risco de ser alocado para outro script.
JG Estiot
3

Sugiro repensar o que você está fazendo. Nunca experimentei um único caso de uso em que esse conhecimento especial seja necessário. O próximo id é um detalhe de implementação muito especial e eu não contaria que ele fosse seguro para ACID.

Faça uma transação simples que atualize sua linha inserida com o último id:

BEGIN;

INSERT INTO payments (date, item, method)
     VALUES (NOW(), '1 Month', 'paypal');

UPDATE payments SET payment_code = CONCAT("sahf4d2fdd45", LAST_INSERT_ID())
     WHERE id = LAST_INSERT_ID();

COMMIT;
Markus Malkusch
fonte
Posso contar um desses casos de uso, estou tentando diagnosticar um problema de produção, então preciso descobrir se a última linha de uma tabela é realmente a última linha ou se houve uma adicionada depois daquela que de alguma forma foi excluída, tabela tem um campo auto_increment nele, portanto, ao encontrar essas informações, posso concluir se a linha foi excluída ou nunca adicionada.
Usman
1
Isso pode funcionar para você, mas eu não confiaria nisso, pois não acho que você tenha qualquer garantia disso: dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html " quando a coluna AUTO_INCREMENT faz parte de um índice de várias colunas), os valores de AUTO_INCREMENT são reutilizados se você excluir a linha com o maior valor de AUTO_INCREMENT em qualquer grupo. "
Markus Malkusch
Obrigado, informações úteis, também de acordo com o auto_incremento do seu link compartilhado pode ser redefinido inserindo um número manualmente, então sim, não é confiável.
Usman
2

Você tem que se conectar ao MySQL e selecionar um banco de dados antes de fazer isso

$table_name = "myTable"; 
$query = mysql_query("SHOW TABLE STATUS WHERE name='$table_name'"); 
$row = mysql_fetch_array($query); 
$next_inc_value = $row["AUTO_INCREMENT"];  
Jondinham
fonte
2

use "mysql_insert_id ()". mysql_insert_id () atua na última consulta realizada, certifique-se de chamar mysql_insert_id () imediatamente após a consulta que gera o valor.

Abaixo estão os exemplos de uso:

<?php
    $link = mysql_connect('localhost', 'username', 'password');
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');

mysql_query("INSERT INTO mytable  VALUES('','value')");
printf("Last inserted record has id %d\n", mysql_insert_id());
    ?>

Espero que o exemplo acima seja útil.

Sagar Chavda
fonte
Obrigado, estou ciente disso.
Sr.Javed Multani
1
mysql_insert_id();

É isso aí :)

user3814281
fonte
1
SELECT id FROM `table` ORDER BY id DESC LIMIT 1

Embora eu duvide de sua produtividade, mas é 100% confiável

Tebe
fonte
Também concordo que esta é a abordagem mais simples. Não sei por que você foi votado contra, mas vou compensar com um voto positivo.
recurse
Eu não mencionei a necessidade de transação, se você não envolvê-lo dentro da transação, esse código é péssimo o mais rápido possível, ele encontra o carregamento real.
Tebe
1
E se a última linha foi excluída? Ou várias linhas mais recentes foram excluídas?
Liam W
Chaves liberadas sem emissão não são usadas a menos que você especifique explicitamente
Tebe
1

usando a resposta de ravi404:

CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
    RETURNS BIGINT
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN

    DECLARE Value BIGINT;

    SELECT
        AUTO_INCREMENT INTO Value
    FROM
        information_schema.tables
    WHERE
        table_name = TableName AND
        table_schema = DATABASE();

    RETURN Value;

END

usando em sua consulta de inserção, para criar um Hash SHA1. ex.:

INSERT INTO
    document (Code, Title, Body)
VALUES (                
    sha1( getAutoincrementalNextval ('document') ),
    'Title',
    'Body'
);
Paulo A. Costa
fonte
Isso sempre funciona? Existe uma condição de corrida se duas inserções acontecerem ao mesmo tempo?
Jmons
0

Melhoria de @ ravi404, no caso de seu deslocamento de incremento automático NÃO SER 1:

SELECT (`auto_increment`-1) + IFNULL(@@auto_increment_offset,1) 
FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = your_table_name
AND table_schema = DATABASE( );

( auto_increment-1): o motor db parece sempre considerar um deslocamento de 1. Portanto, você precisa descartar essa suposição e, em seguida, adicionar o valor opcional de @@ auto_increment_offset, ou padrão para 1: IFNULL (@@ auto_increment_offset, 1)

Olivier
fonte
0

Para mim funciona e parece simples:

 $auto_inc_db = mysql_query("SELECT * FROM my_table_name  ORDER BY  id  ASC ");
 while($auto_inc_result = mysql_fetch_array($auto_inc_db))
 {
 $last_id = $auto_inc_result['id'];
 }
 $next_id = ($last_id+1);


 echo $next_id;//this is the new id, if auto increment is on
Toncsiking
fonte
Totalmente desnecessário atribuir $last_idrepetidamente quando você pode apenas DESC. Seu whilebloco fez um monte de trabalho inútil.
Tiw de
sim, certo ... Acabei de perceber que não é perfeito ... :( final pode-se repetir o id, se ele foi excluído antes ... :(
Toncsiking
0

Se não retornar nenhum AUTO_INCREMENT correto, tente:

ANALYZE TABLE `my_table`;
SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE (TABLE_NAME = 'my_table');

Este cache limpo para mesa, em BD

Vanom
fonte