So erhalten Sie die nächste Auto-Inkrement-ID in MySQL

112

So erhalten Sie die nächste ID in MySQL, um sie in die Tabelle einzufügen

INSERT INTO payments (date, item, method, payment_code)
VALUES (NOW(), '1 Month', 'paypal', CONCAT("sahf4d2fdd45", id))
faressoft
quelle
1
benutze eine auto_incrementSäule
stricke
Möchten Sie die nächste ID oder die ID der Zeile, die Sie gerade einfügen? Das heißt, sollte die ID am Ende des Zahlungscodes die ID der Zeile sein, in der der Zahlungscode gespeichert ist?
Mike
ID der Zeile, die ich gerade
einfüge
6
Verketten Sie in diesem Fall die Werte, wenn Sie sie abrufen, nicht, wenn Sie sie einfügen. Auf diese Weise ist es viel einfacher, und Sie schließen aus, dass Sie die falsche ID erhalten oder ein Update ausführen müssen. Überlegen Sie, was passieren würde, wenn die gerade eingefügte Zeile von einem anderen Client angefordert wird, bevor das Update ausgeführt werden kann: dem Client würde mit einem ungültigen Zahlungscode enden. In einem verkehrsarmen System ist dies möglicherweise nicht der Fall, aber ich sehe keinen Grund, das Risiko einzugehen.
Mike
... oder wie @binaryLV hervorhebt, könnte das Sperren von Ressourcen auch das Problem lösen. Siehe: dev.mysql.com/doc/refman/5.5/en/lock-tables.html
Mike

Antworten:

13

Verwendung LAST_INSERT_ID()aus Ihrer SQL-Abfrage.

Oder

Sie können es auch verwenden mysql_insert_id(), um es mit PHP zu bekommen.

Sarfraz
quelle
11
@Sarfraz: Die Frage war , über die NEXT - ID nicht die LAST , wie Sie erwähnen , sagte LAST_INSERT_ID().
Felipe Pereira
1
Wenn Zeilen in der Tabelle gelöscht werden, ist das
Maximum
Nur eine Notiz von '17 - MySQL * -Funktionen sind veraltet - oben kann mitmysqli_insert_id
treyBake
Wer hat das als Antwort markiert? Die Frage bezieht sich auf die nächste Einfügungs-ID, die nicht zuletzt ist.
Amit Shah
250

Sie können verwenden

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

oder wenn Sie information_schema nicht verwenden möchten, können Sie dies verwenden

SHOW TABLE STATUS LIKE 'table_name'
ravi404
quelle
Vielen Dank für die ersten beiden Optionen. Aber die dritte ist nur die Nummer zwei, die von PHP aufgerufen wird. Ich
bin
1
@ GerardONeill entfernt es
ravi404
3
Da ein Cache zum Abrufen der Daten aus information_schema.tables verwendet wird, funktioniert diese Lösung für MySQL 8 nicht mehr.
Bruno
1
@Bruno kannst du eine Referenz posten?
Mvorisek
1
Dieser offizielle Dokumentstatus TABLES.AUTO_INCREMENTwird zwischengespeichert dev.mysql.com/doc/refman/8.0/en/… . MySQL-Blog hat auch mehrere Beiträge darüber, aber die Systemvariable, die sie erwähnen, scheint veraltet zu sein: mysqlserverteam.com/… mysqlserverteam.com/…
Bruno
50

Sie können den nächsten Wert für die automatische Inkrementierung erhalten, indem Sie Folgendes tun:

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

Beachten Sie, dass Sie dies nicht zum Ändern der Tabelle verwenden sollten. Verwenden Sie stattdessen eine Spalte auto_increment, um dies automatisch zu tun.
Das Problem ist, dass last_insert_id()es rückwirkend ist und somit innerhalb der aktuellen Verbindung garantiert werden kann.
Dieses Baby ist prospektiv und daher nicht pro Verbindung einzigartig und kann nicht als verlässlich angesehen werden.
Nur in einer einzigen Verbindungsdatenbank würde es funktionieren, aber einzelne Verbindungsdatenbanken haben heute die Angewohnheit, morgen mehrere Verbindungsdatenbanken zu werden.

Sehen: SHOW TABLE STATUS

Johan
quelle
5
Ich habe es nicht abgelehnt, aber das Problem beim Versuch, den letzten Wert für die automatische Inkrementierung zu verwenden, besteht darin, dass er möglicherweise nicht der letzte ist, wenn Sie ihn verwenden - unabhängig davon, wie schnell SELECT und das anschließende INSERT ausgeführt werden.
Mike
@ Mike, was ist, wenn es in einer einzelnen Abfrage durchgeführt wird? So etwas wie insert into table_name (field1, field2) select 'constant', auto_increment from information_schema.tables where table_name = 'table_name'? Ich würde die Aktualisierung im after insertTrigger verwenden und last_insert_id()obwohl ...
binaryLV
1
@binaryLV: Je kleiner der Abstand zwischen SELECT und INSERT ist, desto geringer ist die Wahrscheinlichkeit, dass sich der Wert geändert hat, dies schließt ihn jedoch nicht vollständig aus. Stellen Sie sich ein System mit Tausenden von Treffern pro Minute in der Datenbank vor - die Wahrscheinlichkeit, dass sich der Wert geändert hat, steigt dramatisch. Das Sperren von Tabellen oder Zeilen kann dies verhindern, wenn es als einzelne Abfrage ausgeführt wird. Dies hängt jedoch von einem bestimmten Verhalten des Datenbankmoduls ab, das möglicherweise nicht gut dokumentiert ist. Ich würde mit einem späteren gehen, UPDATEwenn ich auch hätte. Aber ich möchte die beiden lieber zur Anzeigezeit verketten und den ganzen Ärger sparen.
Mike
3
SHOW TABLE STATUSerwartet database namenach FROMund 'table name pattern'nach zu sehen LIKE.
X-Yuri
2
Da ein Cache zum Abrufen der Daten aus information_schema.tables verwendet wird, funktioniert diese Lösung für MySQL 8 nicht mehr.
Bruno
14

Dies gibt den automatischen Inkrementwert für die MySQL-Datenbank zurück und ich habe nicht mit anderen Datenbanken nachgefragt. Beachten Sie, dass bei Verwendung einer anderen Datenbank die Abfragesyntax möglicherweise anders ist.

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
quelle
SELECT AUTO_INCREMENT FROM information_schema.tables WHERE table_name = 'your_table_name' und table_schema = 'your_database_name';
17.
10

Die Top-Antwort verwendet PHP MySQL_ für eine Lösung. Ich dachte, ich würde eine aktualisierte PHP MySQLi_- Lösung verwenden, um dies zu erreichen. In diesem Beispiel gibt es keine Fehlerausgabe!

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

Startet das nächste Auto-Inkrement, das in einer Tabelle angezeigt wird.

Hexchaimen
quelle
Da ein Cache zum Abrufen der Daten aus information_schema.tables verwendet wird, funktioniert diese Lösung für MySQL 8 nicht mehr.
Bruno
9

In PHP können Sie dies versuchen:

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

ODER

$result = mysql_query("SHOW TABLE STATUS WHERE `Name` = 'your_table_name'");
$data = mysql_fetch_assoc($result);
$next_increment = $data['Auto_increment'];
Naresh Jain
quelle
5
Denken Sie bei der ersten Methode daran, dass Sie, wenn der Datensatz mit der höchsten ID gelöscht wird, einen neuen Datensatz mit der ID erstellen, die die abgelegte ID früher hatte.
Tom Jenkinson
und wenn der vorherige Schlüssel in anderen Tabellen verwendet wurde und immer noch dort aufbewahrt wird, können Sie mit sehr seltsamer Magie enden
Tebe
Der erste gibt eine falsche ID zurück, wenn Sie den zuletzt eingefügten Datensatz
löschen.
6

Lösung:

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" ist der Name unserer Datenbank

Engel
quelle
5

Eine einfache Abfrage würde genügen SHOW TABLE STATUS LIKE 'table_name'

Raa
quelle
4

Sie können den MySQL-Trigger verwenden

Nick Pavluk
quelle
Das Aktualisieren payment_codeim after insertTrigger scheint die beste Option zu sein.
binaryLV
3

Sie können die ID beim Einfügen nicht verwenden und benötigen sie auch nicht. MySQL kennt die ID nicht einmal, wenn Sie diesen Datensatz einfügen. Sie können einfach "sahf4d2fdd45"in der payment_codeTabelle speichern idund payment_codespäter verwenden.

Wenn Sie Ihren Zahlungscode wirklich benötigen, um die ID zu enthalten, aktualisieren Sie die Zeile nach dem Einfügen, um die ID hinzuzufügen.

Jacob
quelle
+1 Um dies etwas deutlicher zu machen: Wenn Sie den 'neuesten' Wert aus einer Spalte abrufen, wird garantiert, dass er genau zum Zeitpunkt des Abrufs der neueste Wert ist. Es ist möglicherweise nicht der neueste Wert, wenn Sie diesen Wert in einer nachfolgenden Einfügung verwenden. Bei einer Spalte mit automatischer Inkrementierung besteht immer die Möglichkeit, dass zwischen dem Zeitpunkt, zu dem Sie die ID abgerufen haben, und dem Zeitpunkt, zu dem Sie sie an einer anderen Stelle einfügen, ein weiterer Wert hinzugefügt wurde. Wenn Sie auf eine gerade eingefügte Zeile verweisen, ist die Verwendung von LAST_INSERT_ID () in Ordnung. Wenn Sie versuchen, einen eindeutigen Wert sicherzustellen, ist dies nicht der Fall.
Mike
@cularis, MySQL kennt die nächste Auto_Increment-ID, die in der information_schema.tablesTabelle aufgeführt ist.
Johan
1
@faressoft: Wenn Sie einen Zahlungscode haben möchten, der eine eindeutige Zeichenfolge sowie die ID der Zeile enthält, die diesen Zahlungscode enthält, kombinieren Sie die beiden beim Abrufen der Zeile - entweder mit einem SELECT ... CONCAT(payment_code, id)oder in Ihrem Anwendungscode. Sie können das sogar SELECTin ein VIEWeinpacken, sodass Sie immer den richtigen Wert zurückgeben, ohne sich bei jedem SELECT Ihrer App um das CONCAT kümmern zu müssen.
Mike
3

Wofür benötigen Sie die nächste inkrementelle ID?

MySQL erlaubt nur ein Auto-Inkrement-Feld pro Tabelle und muss auch der Primärschlüssel sein, um die Eindeutigkeit zu gewährleisten.

Beachten Sie, dass die nächste Einfügungs-ID bei Verwendung möglicherweise nicht verfügbar ist, wenn Sie sie verwenden, da der Wert, den Sie haben, nur im Rahmen dieser Transaktion liegt. Abhängig von der Auslastung Ihrer Datenbank wird dieser Wert möglicherweise bereits zum Zeitpunkt der nächsten Anforderung verwendet.

Ich würde vorschlagen, dass Sie Ihr Design überprüfen, um sicherzustellen, dass Sie nicht wissen müssen, welcher Wert für die automatische Inkrementierung als Nächstes zugewiesen werden soll

Stephen Senkomago Musoke
quelle
Es ist keine gute Idee, die Art der Anwendung anzunehmen, für die die ID erforderlich ist. Es gibt Anwendungen wie die, an der ich gerade arbeite, die die nächste inkrementelle ID benötigen, und der abgerufene Wert ist nicht gefährdet, einem anderen Skript zugewiesen zu werden.
JG Estiot
3

Ich schlage vor, zu überdenken, was Sie tun. Ich habe noch nie einen einzigen Anwendungsfall erlebt, in dem dieses spezielle Wissen erforderlich ist. Die nächste ID ist ein ganz besonderes Implementierungsdetail, und ich würde nicht damit rechnen, dass sie ACID-sicher ist.

Führen Sie eine einfache Transaktion durch, bei der Ihre eingefügte Zeile mit der letzten ID aktualisiert wird:

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
quelle
Ich kann einen solchen Anwendungsfall nennen, ich versuche ein Produktionsproblem zu diagnostizieren, also muss ich herausfinden, ob die letzte Zeile in einer Tabelle wirklich die letzte Zeile ist oder ob nach der einen Zeile hinzugefügt wurde, die irgendwie gelöscht wurde, Tabelle enthält ein auto_increment-Feld. Wenn ich diese Informationen finde, kann ich schließen, ob die Zeile gelöscht oder nie hinzugefügt wurde.
Usman
1
Das könnte vielleicht für Sie funktionieren, aber ich würde mich nicht darauf verlassen, da ich glaube, dass Sie keine Garantie dafür haben: dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html " Wenn die Spalte AUTO_INCREMENT Teil eines mehrspaltigen Index ist, werden die Werte für AUTO_INCREMENT wiederverwendet, wenn Sie die Zeile mit dem größten Wert für AUTO_INCREMENT in einer Gruppe löschen. "
Markus Malkusch
Vielen Dank, nützliche Informationen, auch gemäß Ihrem freigegebenen Link kann auto_increment zurückgesetzt werden, indem manuell eine Nummer eingefügt wird, also ja nicht zuverlässig.
Usman
2

Sie müssen eine Verbindung zu MySQL herstellen und eine Datenbank auswählen, bevor Sie dies tun können

$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
quelle
2

benutze "mysql_insert_id ()". mysql_insert_id () wirkt auf die zuletzt ausgeführte Abfrage. Rufen Sie mysql_insert_id () unmittelbar nach der Abfrage auf, die den Wert generiert.

Nachfolgend finden Sie ein Anwendungsbeispiel:

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

Ich hoffe, dass das obige Beispiel nützlich ist.

Sagar Chavda
quelle
Danke, ich bin mir dessen bewusst.
Mr.Javed Multani
1
mysql_insert_id();

Das ist es :)

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

Ich bezweifle zwar an seiner Produktivität, aber es ist 100% zuverlässig

Tebe
quelle
Ich stimme auch zu, dass dies der einfachste Ansatz ist. Ich bin mir nicht sicher, warum Sie herabgestimmt wurden, aber ich werde mit einer Gegenstimme ausgleichen.
Rekurs
Ich habe die Notwendigkeit einer Transaktion nicht erwähnt. Wenn Sie sie nicht in eine Transaktion einbinden, ist dieser Code so schnell wie möglich mies, da er dem tatsächlichen Laden entspricht.
Tebe
1
Was ist, wenn die letzte Zeile gelöscht wurde? Oder wurden mehrere letzte Zeilen gelöscht?
Liam W
Freigegebene Schlüssel ohne Probleme werden nur verwendet, wenn Sie sie explizit angeben
Tebe
1

mit der Antwort von 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

Verwenden Sie in Ihrer Einfügeabfrage, um einen SHA1-Hash zu erstellen. Ex.:

INSERT INTO
    document (Code, Title, Body)
VALUES (                
    sha1( getAutoincrementalNextval ('document') ),
    'Title',
    'Body'
);
Paulo A. Costa
quelle
Funktioniert das immer Gibt es Rennbedingungen, wenn zwei Einsätze gleichzeitig erfolgen?
Jmons
0

Verbesserung von @ ravi404, falls Ihr Autoincrement-Offset NICHT 1 ist:

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): Die DB-Engine scheint immer einen Offset von 1 zu berücksichtigen. Sie müssen diese Annahme also verwerfen und dann den optionalen Wert von @@ auto_increment_offset oder standardmäßig 1: IFNULL (@@ auto_increment_offset, 1) hinzufügen.

Olivier
quelle
0

Bei mir funktioniert es und sieht einfach aus:

 $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
quelle
Es ist ziemlich unnötig, sich $last_idwiederholt zuzuweisen, wenn Sie nur können DESC. Ihr whileBlock hat eine Menge nutzloser Arbeit geleistet.
Tiw
ja, richtig ... Ich habe gerade festgestellt, dass es nicht perfekt ist ... :( Ende kann man die ID wiederholen, wenn sie vorher gelöscht wurde ... :(
Toncsiking
0

Wenn Sie kein korrektes AUTO_INCREMENT zurückgeben, versuchen Sie es:

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

Dieser leere Cache für die Tabelle in BD

Vanom
quelle