Як отримати наступний ідентифікатор автоматичного збільшення в mysql


114

Як отримати наступний id в mysql, щоб вставити його в таблицю

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

1
використовувати auto_incrementстовпчик
knittl

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

ідентифікатор рядка, який я зараз вставляю
faressoft

6
У цьому випадку об'єднуйте значення, коли ви їх отримуєте, а не коли ви вставляєте їх. Це набагато простіше, і ви виключаєте отримання неправильного ідентифікатора чи необхідність запуску оновлення - подумайте, що буде, якщо щойно вставлений рядок запитає інший клієнт, перш ніж оновлення матиме шанс запустити: клієнт закінчився б недійсний код оплати. У системі з низьким трафіком це може не статися, але я не бачу сенсу ризикувати.
Майк

... або як зазначає @binaryLV, блокування ресурсів також може вирішити проблему. Дивіться: dev.mysql.com/doc/refman/5.5/uk/lock-tables.html
Майк

Відповіді:


12

Використовуйте за LAST_INSERT_ID()допомогою SQL-запиту.

Або

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


13
@Sarfraz: Питання було про НАСТУПНОМУ ід НЕ ОСТАННІЙ , як ви сказали , згадуючи 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

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, що робити, якщо це робиться в одному запиті? Щось схоже 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 ВІД інформації_schema.tables WHERE 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
Пам’ятайте про перший метод, якщо запис із найвищим ідентифікатором скинутий, ви створите новий запис із ідентифікатором, який раніше був.
Том Дженкінсон

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

Перший повертає неправильний ідентифікатор, якщо ви скинете останній вставлений запис,
Алі Парса

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" - це назва нашої бази даних




3

Ви не можете використовувати ідентифікатор під час вставки, і він вам не потрібен. MySQL навіть не знає ідентифікатора, коли ви вставляєте цю запис. Ви можете просто зберегти "sahf4d2fdd45"в payment_codeтаблиці та використовувати idта payment_codeпізніше.

Якщо вам дійсно потрібен ваш код_плати, щоб у ньому був ідентифікатор, то ОБНОВЛИТИ рядок після вставки для додавання ідентифікатора.


+1 Щоб зробити це трохи більш явним: якщо ви схопите «останнє» значення зі стовпця, воно гарантоване лише останнє значення в той самий момент, коли ви його схопите. Можливо, це не останнє значення, коли ви користуєтесь цим значенням у наступній вставці. У разі стовпця з автоматичним збільшенням завжди є ймовірність, що між часом, коли ви отримали ідентифікатор, та часом, коли ви вставите його в інше місце, буде додано інше значення. Якщо ви посилаєтесь на щойно вставлений рядок, нормально використовувати LAST_INSERT_ID (). Якщо ви намагаєтеся забезпечити унікальну цінність, це не так.
Майк

@cularis, MySQL знає наступний ідентифікатор auto_increment, він вказаний у information_schema.tablesтаблиці.
Йоган

1
@faressoft: Якщо ідея полягає у наявності платіжного коду, який містить унікальний рядок плюс ідентифікатор рядка, що містить цей код оплати, просто об'єднайте два, коли ви отримаєте рядок - або з SELECT ... CONCAT(payment_code, id)кодом, або у коді програми. Ви навіть можете обернути це SELECTв а VIEW, щоб ви завжди повертали потрібне значення, не турбуючись про CONCAT у кожному SELECT зі свого додатка.
Майк

3

Для чого вам потрібен наступний додатковий ідентифікатор?

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

Зауважте, що коли ви отримуєте наступний ідентифікатор вставки, він може бути недоступний при його використанні, оскільки значення, яке ви маєте, знаходиться лише в межах цієї транзакції. Тому залежно від завантаження вашої бази даних, це значення може бути використане до моменту надходження наступного запиту.

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


Недоцільно вважати тип програми, для якої потрібен ідентифікатор. Є такі додатки, як той, над яким я працюю в даний момент, який потребує наступного інкрементального ідентифікатора, і отримане значення не загрожує присвоєнням іншому сценарію.
JG Estiot

3

Я пропоную переосмислити те, що ви робите. Я ніколи не стикався з одним випадком використання, коли потрібні спеціальні знання. Наступний ідентифікатор - це дуже особлива деталь реалізації, і я не розраховував би на те, щоб це було безпечним для кислоти.

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

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;

Я можу сказати один із таких випадків використання, я намагаюся діагностувати виробничу проблему, тому мені потрібно з’ясувати, чи є останній рядок у таблиці справді останнім рядком, чи був доданий після цього який-небудь видалений, таблиця в ньому є поле авто-збільшення, тому, знайшовши цю інформацію, я можу зробити висновок, чи рядок був видалений чи ніколи не доданий.
Усман

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% надійно


Я теж згоден, що це найпростіший підхід. Не впевнений, чому ви були зняті з голосу, але я компенсую внесок.
повтор

Я не згадував про необхідність трансакції, якщо ви не загорнете її всередину транзакції, цей код є паршивим, оскільки він відповідає реальному завантаженню.
Тебе

1
Що робити, якщо останню рядок було видалено? Або кілька останніх рядків видалено?
Ліам Ш

Невипущені, звільнені ключі не використовуються, якщо ви не вкажете їх прямо
Tebe

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блок зробив безліч марної роботи.
Тів

так, правильно ... Я щойно зрозумів, що це не ідеально ... :( в кінці можна повторити ідентифікатор, якщо він був видалений раніше ... :(
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.