Как получить следующий идентификатор автоинкремента в mysql


114

Как получить следующий идентификатор в mysql, чтобы вставить его в таблицу

INSERT INTO payments (date, item, method, payment_code)
VALUES (NOW(), '1 Month', 'paypal', CONCAT("sahf4d2fdd45", id))

1
использовать auto_incrementстолбик
knittl

Вам нужен следующий идентификатор или идентификатор строки, которую вы сейчас вставляете? То есть должен ли идентификатор в конце кода платежа быть идентификатором строки, в которой хранится код платежа?
Майк,

id строки, которую я сейчас вставляю
faressoft

6
В этом случае объединяйте значения при их получении, а не при их вставке. Это намного проще, и вы исключаете получение неправильного идентификатора или необходимость запускать обновление - подумайте, что произойдет, если строка, которую вы только что вставили, будет запрошена другим клиентом до того, как обновление успеет запуститься: клиент закончится неверным кодом платежа. В системе с низким трафиком этого может и не произойти, но я не вижу смысла рисковать.
Майк,

... или, как указывает @binaryLV, блокировка ресурсов также может решить проблему. См .: dev.mysql.com/doc/refman/5.5/en/lock-tables.html
Майк,

Ответы:


12

Используйте LAST_INSERT_ID()из вашего SQL-запроса.

Или

Вы также можете использовать его mysql_insert_id()для получения с помощью PHP.


13
@Sarfraz: Вопрос касался NEXT id, а не ПОСЛЕДНЕГО, как вы сказали LAST_INSERT_ID().
Фелипе Перейра

1
Если в таблице удалить строки, максимальное значение будет неправильным
peterchaula

просто примечание от '17 - функции mysql * устарели - выше можно сделать с помощьюmysqli_insert_id
treyBake

кто пометил это как ответ? вопрос касается следующего идентификатора вставки, а не последнего.
Амит Шах,

253

Ты можешь использовать

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

или если вы не хотите использовать information_schema, вы можете использовать это

SHOW TABLE STATUS LIKE 'table_name'

Спасибо за первые два варианта .. Но третий - это всего лишь номер два, вызываемый из PHP .. Не уверен, что делает это быстрее в больших базах данных ...
Джерард Онилл

1
@GerardONeill Удалено
ravi404

3
поскольку для извлечения данных из information_schema.tables используется кеш, это решение больше не работает для mysql 8.
Бруно

1
@Bruno вы можете опубликовать ссылку?
mvorisek 02

1
В этом официальном документе указано, что TABLES.AUTO_INCREMENTнаходится в кеше dev.mysql.com/doc/refman/8.0/en/… . В блоге Mysql также есть несколько сообщений об этом, но система, которую они упоминают, кажется устаревшей: mysqlserverteam.com/… mysqlserverteam.com/…
Бруно

50

Вы можете получить следующее значение автоинкремента, выполнив:

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

Обратите внимание, что вы не должны использовать это для изменения таблицы, вместо этого используйте столбец auto_increment, чтобы сделать это автоматически.
Проблема в том, что last_insert_id()это ретроспективно и, следовательно, может быть гарантировано в рамках текущего соединения.
Этот ребенок перспективен и, следовательно, не уникален для каждого соединения, и на него нельзя положиться.
Только в базе данных с одним подключением это могло бы работать, но сегодня базы данных с одним подключением имеют привычку завтра превращаться в базы данных с несколькими подключениями.

Видеть: SHOW TABLE STATUS


5
Я не понижал его, но проблема с попыткой использовать последнее автоматически увеличивающееся значение заключается в том, что оно может быть не последним к тому времени, когда вы начнете его использовать - независимо от того, как быстро выполняется SELECT и последующий INSERT.
Mike

@Mike, а что, если это делается одним запросом? Что-то вроде insert into table_name (field1, field2) select 'constant', auto_increment from information_schema.tables where table_name = 'table_name'? Я бы использовал обновление в after insertтриггере и last_insert_id(), хотя ...
binaryLV

1
@binaryLV: чем меньше разрыв между SELECT и INSERT, тем меньше вероятность того, что значение изменится, но это не исключает полностью. Представьте себе систему с тысячами посещений в минуту в базе данных - шансы на изменение значения резко возрастают. Блокировка таблицы или строки может предотвратить это, если она выполняется как единый запрос, но это зависит от определенного поведения механизма базы данных, которое может быть плохо документировано. Я бы пошел с последующим, UPDATEесли бы тоже. Но я бы предпочел просто объединить их во время отображения и избавить от лишних хлопот.
Майк,

3
SHOW TABLE STATUSожидает увидеть database nameпосле FROMи 'table name pattern'после LIKE.
x-yuri

2
поскольку для извлечения данных из information_schema.tables используется кеш, это решение больше не работает для mysql 8.
Бруно,

15

Это вернет значение автоматического увеличения для базы данных MySQL, и я не проверял с другими базами данных. Обратите внимание, что если вы используете любую другую базу данных, синтаксис запроса может быть другим.

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();

ВЫБЕРИТЕ AUTO_INCREMENT ИЗ information_schema.tables, ГДЕ table_name = 'your_table_name' и table_schema = 'your_database_name';
LJay

10

В верхнем ответе для решения используется PHP MySQL_ , и я подумал, что поделюсь обновленным решением PHP MySQLi_ для достижения этой цели. В этом примере нет вывода ошибок!

$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'];

Выбрасывает следующее автоматическое приращение, появляющееся в таблице.


поскольку для извлечения данных из information_schema.tables используется кеш, это решение больше не работает для mysql 8.
Бруно,

9

В PHP вы можете попробовать следующее:

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

ИЛИ

$result = mysql_query("SHOW TABLE STATUS WHERE `Name` = 'your_table_name'");
$data = mysql_fetch_assoc($result);
$next_increment = $data['Auto_increment'];

5
Помните о первом методе, если будет отброшена запись с наивысшим идентификатором, тогда вы создадите новую запись с идентификатором, который использовался ранее.
Том Дженкинсон

и если предыдущий ключ использовался в других таблицах и все еще хранится там, вы можете получить очень странную магию
Тебе,

первый возвращает неправильный идентификатор, если вы отбрасываете последнюю вставленную запись,
Али Парса

6

Решение:

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" - это название нашей базы данных.


5

Простой запрос подойдет SHOW TABLE STATUS LIKE 'table_name'



3

Вы не можете использовать идентификатор при вставке, он вам и не нужен. MySQL даже не знает ID, когда вы вставляете эту запись. Вы можете просто сохранить "sahf4d2fdd45"в payment_codeтаблице и использовать idиpayment_code дальнейшем.

Если вам действительно нужен ваш payment_code, чтобы в нем был идентификатор, ОБНОВИТЕ строку после вставки, чтобы добавить идентификатор.


+1 Чтобы сделать это немного более явным: если вы берете «последнее» значение из столбца, оно гарантированно будет последним значением только в тот момент, когда вы его получили. Это может быть не последнее значение, когда вы собираетесь использовать это значение в последующей вставке. В случае столбца с автоматическим приращением всегда есть вероятность, что другое значение было добавлено между временем, когда вы получили идентификатор, и временем, когда вы вставили его в другое место. Если вы ссылаетесь на только что вставленную строку, можно использовать LAST_INSERT_ID (). Если вы пытаетесь обеспечить уникальное значение, это не так.
Майк,

@cularis, MySQL знает следующий идентификатор auto_increment, он указан в information_schema.tablesтаблице.
Johan

1
@faressoft: если идея состоит в том, чтобы иметь код платежа, который состоит из уникальной строки и идентификатора строки, содержащей этот код платежа, просто объедините их при получении строки - либо с SELECT ... CONCAT(payment_code, id), либо в коде вашего приложения. Вы даже можете заключить SELECTв a VIEW, чтобы всегда возвращать правильное значение, не беспокоясь о CONCAT в каждом SELECT из вашего приложения.
Майк,

3

Для чего вам нужен следующий инкрементный идентификатор?

MySQL допускает только одно поле с автоинкрементом для каждой таблицы, и оно также должно быть первичным ключом, чтобы гарантировать уникальность.

Обратите внимание, что когда вы получаете следующий идентификатор вставки, он может быть недоступен при его использовании, поскольку имеющееся у вас значение находится только в рамках этой транзакции. Следовательно, в зависимости от нагрузки на вашу базу данных, это значение может уже использоваться к моменту поступления следующего запроса.

Я бы посоветовал вам пересмотреть свой дизайн, чтобы убедиться, что вам не нужно знать, какое значение автоинкремента назначить следующим


Не рекомендуется предполагать, какое приложение требует ID. Существуют приложения, подобные тому, над которым я работаю в данный момент, которому требуется следующий инкрементный идентификатор, и полученное значение не находится в опасности быть выделенным другому сценарию.
JG Estiot

3

Предлагаю переосмыслить то, что вы делаете. Я никогда не встречал ни одного случая, когда требовались бы эти специальные знания. Следующий идентификатор - это особая деталь реализации, и я бы не стал рассчитывать на то, что он безопасен для ACID.

Сделайте одну простую транзакцию, которая обновит вашу вставленную строку с последним идентификатором:

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;

Я могу назвать один такой вариант использования, я пытаюсь диагностировать производственную проблему, поэтому мне нужно выяснить, действительно ли последняя строка в таблице является последней строкой или была добавлена ​​одна после той, которая каким-то образом была удалена, таблица имеет поле auto_increment, поэтому, найдя эту информацию, я могу сделать вывод, была ли строка удалена или никогда не добавлялась.
Усман

1
Возможно, это сработает для вас, но я бы не стал на это полагаться, поскольку не думаю, что у вас есть на это гарантии: dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html " когда столбец AUTO_INCREMENT является частью индекса с несколькими столбцами), значения AUTO_INCREMENT используются повторно, если вы удаляете строку с наибольшим значением AUTO_INCREMENT в любой группе ».
Маркус Малкуш

Спасибо, полезная информация, также согласно вашей общей ссылке auto_increment можно сбросить, вставив вручную номер, так что да, это ненадежно.
Усман

2

Вам необходимо подключиться к MySQL и выбрать базу данных, прежде чем вы сможете это сделать.

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

2

используйте mysql_insert_id (). mysql_insert_id () воздействует на последний выполненный запрос, обязательно вызовите mysql_insert_id () сразу после запроса, который генерирует значение.

Ниже приведен пример использования:

<?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());
    ?>

Надеюсь, приведенный выше пример окажется полезным.


Спасибо, я в курсе.
Мистер Джавед Мултани


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

Хотя сомневаюсь в его продуктивности, но надежен на 100%


Я тоже согласен, что это самый простой подход. Не уверен, почему вас проголосовали против, но я компенсирую это голосом за.
recurse

Я не упоминал о необходимости транзакции, если вы не обернете его внутри транзакции, этот код паршивый, поскольку он соответствует реальной загрузке.
Тебе,

1
Что делать, если последняя строка была удалена? Или несколько последних строк были удалены?
Liam W

Не связанные с проблемами, освобожденные ключи не используются, если вы не укажете это явно
Тебе,

1

используя ответ 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

используя в запросе на вставку, чтобы создать хеш SHA1. напр .:

INSERT INTO
    document (Code, Title, Body)
VALUES (                
    sha1( getAutoincrementalNextval ('document') ),
    'Title',
    'Body'
);

Это всегда работает? Есть ли условия гонки, если две вставки выполняются одновременно?
Jmons

0

Улучшение @ ravi404, если ваше смещение автоинкремента НЕ 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): механизм db, кажется, всегда учитывает смещение 1. Поэтому вам нужно отказаться от этого предположения, а затем добавить необязательное значение @@ auto_increment_offset или значение по умолчанию 1: IFNULL (@@ auto_increment_offset, 1)


0

Для меня это работает и выглядит просто:

 $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

Совершенно ненужно назначать $last_idповторно, когда можно просто DESC. Ваш whileблок проделал кучу бесполезной работы.
Tiw

да, верно ... Я только что понял, что это не идеально ... :( В конце можно повторить идентификатор, если он был удален раньше ... :(
Toncsiking

0

Если не возвращается правильный AUTO_INCREMENT, попробуйте:

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

Этот чистый кеш для таблицы в BD

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.