Wie erhalte ich die ID der zuletzt aktualisierten Zeile in MySQL?

134

Wie erhalte ich die ID der zuletzt aktualisierten Zeile in MySQL mit PHP?

Avinash
quelle
2
mysqli_insert_id ($ link) gibt genau die ID der zuletzt aktualisierten Zeile zurück. Ich benutze diese Funktion in meinen Projekten für den gleichen Zweck. Sie können es sowohl in synchronen als auch in asynchronen Abfragen verwenden. Fügen Sie einfach $ lastupdated_row_id = mysqli_insert_id ($ link) in Ihren Code ein und es wird für Sie funktionieren.
Naeem Ul Wahhab
1
Kennen Sie die ID der Zeile nicht bereits, wenn Sie aktualisieren? Ich denke, es muss einige Fälle geben, in denen Sie dies nicht tun.
JCharette
1
Sie verwenden wahrscheinlich eine where-Klausel in Ihrer Aktualisierungsabfrage. Warum können Sie nicht dieselbe where-Klausel in der Auswahlabfrage verwenden? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Salman A

Antworten:

236

Ich habe eine Antwort auf dieses Problem gefunden :)

SET @update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT @update_id := id)
WHERE some_other_column = 'blah' LIMIT 1; 
SELECT @update_id;

EDIT von aefxx

Diese Technik kann weiter erweitert werden, um die ID jeder Zeile abzurufen, die von einer Aktualisierungsanweisung betroffen ist:

SET @uids := null;
UPDATE footable
   SET foo = 'bar'
 WHERE fooid > 5
   AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) );
SELECT @uids;

Dies gibt eine Zeichenfolge mit allen durch ein Komma verketteten IDs zurück.

Pomyk
quelle
6
Ich kann nicht glauben, dass dies 0 positive Stimmen hatte, und der Kommentar mysql_insert_id (), den das OP überhaupt nicht verlangt hat, hat 13. Danke Pomyk, ein kluger Trick!
Jaka Jančar
1
Da Sie eine WHEREKlausel haben, können Sie einfach dieselbe WHEREKlausel in Ihrer nächsten Abfrage verwendenSELECT id FROM footable WHERE fooid > 5
Salman A
4
Vielleicht versteht das jeder, aber wenn Sie mysql_query () verwenden; Sie müssen dies in drei verschiedene Anrufe aufteilen, aber es wird funktionieren.
rael_kid
8
Es müssen nicht einmal Variablen verwendet werden. LAST_INSERT_ID()kann ein Argument akzeptieren, das den Wert festlegt, der beim nächsten Aufruf von zurückgegeben wird LAST_INSERT_ID(). Zum Beispiel : UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Jetzt SELECT LAST_INSERT_ID();wird die aktualisierte ID zurückgegeben. Weitere Informationen finden Sie in der Antwort von newtover.
Joel
3
@SteveChilds Ich habe gerade die Frage von newtover kommentiert und möchte eine Lösung für die von Ihnen beschriebene Falle hinzufügen. Dies setzt LAST_INSERT_ID auf 0, wenn UPDATE nichts enthält : UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. Da jedoch nicht mehrere IDs abgerufen werden, ist diese Antwort überlegen.
Martinczerwi
33

Hm, ich bin überrascht, dass ich unter den Antworten nicht die einfachste Lösung sehe.

Angenommen, es item_idhandelt sich um eine ganzzahlige Identitätsspalte in der itemsTabelle, und Sie aktualisieren Zeilen mit der folgenden Anweisung:

UPDATE items
SET qwe = 'qwe'
WHERE asd = 'asd';

Um die letzte betroffene Zeile direkt nach der Anweisung zu ermitteln, sollten Sie die Anweisung geringfügig wie folgt aktualisieren:

UPDATE items
SET qwe = 'qwe',
    item_id=LAST_INSERT_ID(item_id)
WHERE asd = 'asd';
SELECT LAST_INSERT_ID();

Wenn Sie nur wirklich geänderte Zeilen aktualisieren müssen, müssen Sie eine bedingte Aktualisierung der item_id über die LAST_INSERT_ID hinzufügen, um zu überprüfen, ob sich die Daten in der Zeile ändern werden.

Newtover
quelle
3
Es ist für mehrere Benutzer sicher, da mehrere Clients die UPDATE-Anweisung ausgeben und mit der SELECT-Anweisung (oder mysql_insert_id ()) ihren eigenen Sequenzwert abrufen können, ohne andere Clients zu beeinflussen oder davon betroffen zu sein, die ihre eigenen Sequenzwerte generieren. Wie pro dev.mysql.com/doc/refman/5.0/en/...
brutuscat
1
Wird dadurch die item_id nicht auf den zuletzt eingefügten Datensatz gesetzt?
Arleslie
2
@arleslie, wenn Sie dem Link zu den Dokumenten im Kommentar des Brutuscat oben folgen, werden Sie sehen, dass dies nicht der Fall ist. Dies ist das beabsichtigte Verhalten genau für den Fall.
Newtover
1
Dies ist in der Tat die richtige Antwort. Obwohl die Abfrage etwas kontraintuitiv zu sein scheint, ist dies genau das, was die MySQL-Dokumentation vorschreibt.
Timothy Zorn
3
Falls die Abfrage Sie verwirrt, da LAST_INSERT_ID (Ausdruck) den Wert von Ausdruck für den UPDATE-Aufruf zurückgibt, können Sie ihn auch folgendermaßen verwenden:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi
14

Dies ist offiziell einfach, aber bemerkenswert kontraintuitiv. Wenn Sie tun:

update users set status = 'processing' where status = 'pending'
limit 1

Ändern Sie es in dieses:

update users set status = 'processing' where status = 'pending'
and last_insert_id(user_id) 
limit 1

Das Hinzufügen von last_insert_id(user_id)in der whereKlausel weist MySQL an , seine interne Variable auf die ID der gefundenen Zeile zu setzen. Wenn Sie einen Wert an last_insert_id(expr)like übergeben, wird dieser Wert zurückgegeben, der bei IDs wie hier immer eine positive Ganzzahl ist und daher immer als true ausgewertet wird, ohne die where-Klausel zu beeinträchtigen. Dies funktioniert nur, wenn tatsächlich eine Zeile gefunden wurde. Denken Sie also daran, die betroffenen Zeilen zu überprüfen. Sie können die ID dann auf verschiedene Arten erhalten.

MySQL last_insert_id()

Sie können Sequenzen generieren, ohne LAST_INSERT_ID () aufzurufen. Die Verwendung dieser Funktion besteht jedoch darin, dass der ID-Wert auf dem Server als letzter automatisch generierter Wert beibehalten wird. Es ist für mehrere Benutzer sicher, da mehrere Clients die UPDATE-Anweisung ausgeben und mit der SELECT-Anweisung (oder mysql_insert_id ()) ihren eigenen Sequenzwert abrufen können, ohne andere Clients zu beeinflussen oder davon betroffen zu sein, die ihre eigenen Sequenzwerte generieren.

MySQL mysql_insert_id()

Gibt den Wert zurück, der für eine AUTO_INCREMENT-Spalte von der vorherigen INSERT- oder UPDATE-Anweisung generiert wurde. Verwenden Sie diese Funktion, nachdem Sie eine INSERT-Anweisung in einer Tabelle ausgeführt haben, die ein AUTO_INCREMENT-Feld enthält, oder INSERT oder UPDATE verwendet haben, um einen Spaltenwert mit LAST_INSERT_ID (Ausdruck) festzulegen.

Der Grund für die Unterschiede zwischen LAST_INSERT_ID () und mysql_insert_id () ist, dass LAST_INSERT_ID () in Skripten einfach zu verwenden ist, während mysql_insert_id () versucht, genauere Informationen darüber bereitzustellen, was mit der Spalte AUTO_INCREMENT geschieht.

PHP mysqli_insert_id()

Durch Ausführen einer INSERT- oder UPDATE-Anweisung mit der Funktion LAST_INSERT_ID () wird auch der von der Funktion mysqli_insert_id () zurückgegebene Wert geändert.

Alles zusammen:

$affected_rows = DB::getAffectedRows("
    update users set status = 'processing' 
    where status = 'pending' and last_insert_id(user_id) 
    limit 1"
);
if ($affected_rows) {
    $user_id = DB::getInsertId();
}

(Zu Ihrer Information, diese DB-Klasse ist hier .)

Vladimir Kornea
quelle
Wichtig zu beachten: Dies ist für mehrere Verbindungen sicher. Der beibehaltene Wert für last_insert_id oder mysql_insert_id (und möglicherweise mysqli_insert_id, den ich nicht überprüft habe) gilt pro Verbindung. Genial!
Ryan S
10

Dies ist die gleiche Methode wie die Antwort von Salman A, aber hier ist der Code, den Sie tatsächlich benötigen, um dies zu tun.

Bearbeiten Sie zunächst Ihre Tabelle so, dass sie automatisch nachverfolgt, wann immer eine Zeile geändert wird. Entfernen Sie die letzte Zeile, wenn Sie nur wissen möchten, wann eine Zeile ursprünglich eingefügt wurde.

ALTER TABLE mytable
ADD lastmodified TIMESTAMP 
    DEFAULT CURRENT_TIMESTAMP 
    ON UPDATE CURRENT_TIMESTAMP;

Um die letzte aktualisierte Zeile herauszufinden, können Sie diesen Code verwenden.

SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;

Dieser Code stammt aus MySQL vs PostgreSQL: Hinzufügen einer Spalte "Letzte geänderte Zeit" zu einer Tabelle und MySQL-Handbuch: Sortieren von Zeilen . Ich habe es gerade zusammengebaut.

Chad von Nau
quelle
7
Diese Methode kann die falsche ID abrufen, wenn die zweite Einfügung unmittelbar nach der ersten Einfügeabfrage erfolgt. Wenn wir jedoch bei dieser Abfrage 'WHERE' verwenden, dh SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1 WHERE (einige Bedingungen im Zusammenhang mit der letzten Einfügeabfrage), kann dies das Abrufen der falschen ID verhindern.
Naeem Ul Wahhab
1
@ TheNoble-Coder Das ist wahr. Wenn Sie die ID einer Zeile erhalten möchten, die von einer bestimmten Aktualisierungsabfrage betroffen ist, verwenden Sie die Pomyk-Technik. Diese Technik ist hier nützlicher, wenn sie asynchron verwendet wird und Sie nur das absolute letzte Update wünschen.
Chad von Nau
5

Abfrage:

$sqlQuery = "UPDATE 
            update_table 
        SET 
            set_name = 'value' 
        WHERE 
            where_name = 'name'
        LIMIT 1;";

PHP-Funktion:

function updateAndGetId($sqlQuery)
{
    mysql_query(str_replace("SET", "SET id = LAST_INSERT_ID(id),", $sqlQuery));
    return mysql_insert_id();
}

Es ist Arbeit für mich;)

GigolNet Guigolachvili
quelle
Ich mochte das gleiche, lief aber anders ref: forums.mysql.com/read.php?52,390616,390619
3

Weiter mehr zur oben akzeptierten Antwort
Für diejenigen, die sich über :=& wunderten=

Ein signifikanter Unterschied zwischen :=und =, und das ist, dass er :=überall als Operator für die Variablenzuweisung funktioniert, während er =nur in SET-Anweisungen so funktioniert, und überall sonst als Vergleichsoperator.

So SELECT @var = 1 + 1;verläßt @varunverändert und gibt einen boolean (1 oder 0 in Abhängigkeit von dem aktuellen Wert von @var), während SELECT @var := 1 + 1;ändern @varzu 2 und 2 zurückkehren . [Quelle]

Anon30
quelle
Hey danke. Was sie bedeuten, ist tatsächlich interessanter als die oben akzeptierte Antwort.
Grün
2

Hey, ich brauchte nur so einen Trick - ich habe ihn auf eine andere Weise gelöst, vielleicht funktioniert er für dich. Beachten Sie, dass dies keine skalierbare Lösung ist und für große Datenmengen sehr schlecht ist.

Teilen Sie Ihre Anfrage in zwei Teile -

Wählen Sie zunächst die IDs der Zeilen aus, die Sie aktualisieren möchten, und speichern Sie sie in einer temporären Tabelle.

Führen Sie zweitens das ursprüngliche Update mit der Bedingung in der Update-Anweisung aus, die in geändert wurde where id in temp_table.

Und Parallelität zu gewährleisten, müssen Sie sperren , bevor diese zwei Schritte , um den Tisch und lassen Sie dann die Sperre am Ende.

Auch dies funktioniert für mich für eine Abfrage, die mit endet limit 1, sodass ich nicht einmal eine temporäre Tabelle verwende, sondern einfach eine Variable, um das Ergebnis der ersten zu speichern select.

Ich bevorzuge diese Methode, da ich weiß, dass ich immer nur eine Zeile aktualisieren werde und der Code unkompliziert ist.

Olamundo
quelle
2
SET @uids := "";
UPDATE myf___ingtable
   SET id = id
   WHERE id < 5
  AND ( SELECT @uids := CONCAT_WS(',', CAST(id AS CHAR CHARACTER SET utf8), @uids) );
SELECT @uids;

Ich musste die ID CAST (keine Ahnung warum) ... oder ich kann den @uids-Inhalt nicht bekommen (es war ein Blob). Übrigens vielen Dank für die Antwort von Pomyk!

Gromish
quelle
2

Die ID der zuletzt aktualisierten Zeile ist dieselbe ID, die Sie in der 'updateQuery' verwenden, um diese Zeile zu finden und zu aktualisieren. Speichern Sie also einfach diese ID (rufen Sie sie an), wie Sie möchten.

last_insert_id()hängt von der AUTO_INCREMENT, aber der zuletzt aktualisierten ID nicht ab.

Driada
quelle
3
Was ist, wenn das Update nicht über eine ID, sondern über einen anderen Satz von Attributen erfolgt?
Sebas
2

Meine Lösung ist, zuerst die "ID" (@uids) mit dem Befehl select zu bestimmen und diese ID nach dem Aktualisieren mit @uids zu aktualisieren.

SET @uids := (SELECT id FROM table WHERE some = 0 LIMIT 1);
UPDATE table SET col = 1 WHERE id = @uids;SELECT @uids;

es hat bei meinem Projekt funktioniert.

Ahmet Uğur
quelle
1

Wenn Sie nur Einfügungen vornehmen und eine aus derselben Sitzung wünschen, gehen Sie wie in der Antwort von peirix beschrieben vor. Wenn Sie Änderungen vornehmen, müssen Sie Ihr Datenbankschema ändern, um zu speichern, welcher Eintrag zuletzt aktualisiert wurde.

Wenn Sie die ID der letzten Änderung wünschen, die möglicherweise aus einer anderen Sitzung stammt (dh nicht die, die nur durch den derzeit ausgeführten PHP-Code erstellt wurde, sondern als Antwort auf eine andere Anforderung), können Sie eine hinzufügen TIMESTAMP-Spalte in Ihrer Tabelle mit dem Namen last_modified ( Informationen finden Sie unter http://dev.mysql.com/doc/refman/5.1/en/datetime.html ) . Setzen Sie dann beim Aktualisieren last_modified = CURRENT_TIME.

Nachdem Sie dies festgelegt haben, können Sie eine Abfrage wie folgt verwenden: SELECT id FROM table ORDER BY last_modified DESC LIMIT 1; um die zuletzt geänderte Zeile zu erhalten.

a1kmm
quelle
-9

Keine Notwendigkeit für so langen MySQL-Code. In PHP sollte die Abfrage ungefähr so ​​aussehen:

$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error');
$lastUpdatedId = mysql_insert_id();
Driada
quelle