mysqli_insert_id ($ link) zwróci dokładnie identyfikator ostatniego zaktualizowanego wiersza. Używam tej funkcji w moich projektach w tym samym celu. Możesz go używać zarówno w zapytaniach synchronicznych, jak i asynchronicznych. Po prostu wstaw $ lastupdated_row_id = mysqli_insert_id ($ link) do swojego kodu i będzie działać dla Ciebie.
Naeem Ul Wahhab,
1
Czy nie znasz już identyfikatora wiersza po aktualizacji? Myślę, że muszą być przypadki, w których tego nie robisz.
jlcharette
1
Prawdopodobnie używasz klauzuli Where w zapytaniu aktualizującym, dlaczego nie możesz użyć tej samej klauzuli Where w zapytaniu wybierającym? UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1?
Salman A
Odpowiedzi:
242
Znalazłem odpowiedź na ten problem :)
SET @update_id := 0;
UPDATE some_table SET column_name = 'value', id = (SELECT @update_id := id)
WHERE some_other_column = 'blah'LIMIT1;
SELECT @update_id;
EDYCJA przez aefxx
Technikę tę można dodatkowo rozszerzyć, aby pobrać identyfikator każdego wiersza, na który ma wpływ instrukcja aktualizacji:
Nie mogę uwierzyć, że to miało 0 głosów poparcia, a komentarz mysql_insert_id (), o który w ogóle nie pytał OP, ma 13. Dzięki Pomyk, sprytna sztuczka!
Jaka Jančar
1
Ponieważ masz WHEREklauzulę, możesz po prostu użyć tej samej WHEREklauzuli w następnym zapytaniuSELECT id FROM footable WHERE fooid > 5
Salman A
4
Może każdy to rozumie, ale jeśli używasz mysql_query (); musisz podzielić to na trzy różne rozmowy, ale to zadziała.
rael_kid
8
Nie ma nawet potrzeby używania zmiennych. LAST_INSERT_ID()może przyjąć argument, który ustawi wartość zwracaną przez następne wywołanie funkcji LAST_INSERT_ID(). Na przykład: UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';. Teraz SELECT LAST_INSERT_ID();zwróci zaktualizowany identyfikator. Aby uzyskać więcej informacji, zobacz odpowiedź newtover.
Joel
3
@SteveChilds Właśnie komentowałem pytanie newtovera i chcę dodać rozwiązanie opisanej pułapki. Te zestawy LAST_INSERT_ID 0 jeśli nie ma nic do UPDATE: UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);. Jednak nie pobiera wielu identyfikatorów, więc ta odpowiedź jest lepsza.
martinczerwi
34
Hm, dziwię się, że wśród odpowiedzi nie widzę najłatwiejszego rozwiązania.
Załóżmy, że item_idjest to kolumna będąca liczbą całkowitą w itemstabeli i aktualizujesz wiersze za pomocą następującej instrukcji:
UPDATE items
SET qwe = 'qwe'WHERE asd = 'asd';
Następnie, aby poznać najnowszy wiersz, którego dotyczy problem, tuż po instrukcji, należy nieznacznie zaktualizować instrukcję do następującego:
UPDATE items
SET qwe = 'qwe',
item_id=LAST_INSERT_ID(item_id)
WHERE asd = 'asd';
SELECTLAST_INSERT_ID();
Jeśli chcesz zaktualizować tylko naprawdę zmieniony wiersz, musisz dodać warunkową aktualizację item_id poprzez LAST_INSERT_ID sprawdzając, czy dane zmienią się w wierszu.
Jest bezpieczny dla wielu użytkowników, ponieważ wielu klientów może wydać instrukcję UPDATE i uzyskać własną wartość sekwencji za pomocą instrukcji SELECT (lub mysql_insert_id ()), bez wpływu lub wpływu na innych klientów, którzy generują własne wartości sekwencji. Zgodnie z dev.mysql.com/doc/refman/5.0/en/…
brutuscat
1
Czy to nie ustawi item_id na ostatnio wstawiony rekord?
arleslie
2
@arleslie, jeśli podążasz za linkiem do dokumentów w komentarzu brutuscata powyżej, zobaczysz, że nie. Jest to zamierzone zachowanie dokładnie w przypadku.
newtover
2
To jest rzeczywiście prawidłowa odpowiedź. Chociaż zapytanie wydaje się nieco sprzeczne z intuicją, to jest dokładnie to, co mówi Dokumentacja MySQL.
Timothy Zorn,
3
W przypadku, gdy zapytanie jest mylące cię, ponieważ LAST_INSERT_ID (wyrażenie) zwróci wartość wyraż na wezwanie UPDATE można również używać go tak:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
martinczerwi
14
Jest to oficjalnie proste, ale niezwykle sprzeczne z intuicją. Jeśli robisz:
Dodanie last_insert_id(user_id)w whereklauzuli mówi MySQL, aby ustawić swoją wewnętrzną zmienną na identyfikator znalezionego wiersza. Kiedy przekazujesz taką wartość last_insert_id(expr), w końcu zwraca tę wartość, która w przypadku identyfikatorów takich jak tutaj jest zawsze dodatnią liczbą całkowitą i dlatego zawsze zwraca wartość true, nigdy nie kolidując z klauzulą where. Działa to tylko wtedy, gdy rzeczywiście znaleziono jakiś wiersz, więc pamiętaj, aby sprawdzić wiersze, których dotyczy problem. Następnie możesz uzyskać identyfikator na wiele sposobów.
Możesz generować sekwencje bez wywoływania LAST_INSERT_ID (), ale użyteczność korzystania z tej funkcji w ten sposób polega na tym, że wartość ID jest utrzymywana na serwerze jako ostatnia automatycznie wygenerowana wartość. Jest bezpieczny dla wielu użytkowników, ponieważ wielu klientów może wydać instrukcję UPDATE i uzyskać własną wartość sekwencji za pomocą instrukcji SELECT (lub mysql_insert_id ()), bez wpływu lub wpływu innych klientów, którzy generują własne wartości sekwencji.
Zwraca wartość wygenerowaną dla kolumny AUTO_INCREMENT przez poprzednią instrukcję INSERT lub UPDATE. Użyj tej funkcji po wykonaniu instrukcji INSERT w tabeli zawierającej pole AUTO_INCREMENT lub po użyciu instrukcji INSERT lub UPDATE do ustawienia wartości kolumny z LAST_INSERT_ID (wyrażenie).
Przyczyną różnic między LAST_INSERT_ID () a mysql_insert_id () jest to, że LAST_INSERT_ID () jest łatwy w użyciu w skryptach, podczas gdy mysql_insert_id () próbuje podać dokładniejsze informacje o tym, co dzieje się z kolumną AUTO_INCREMENT.
Ważna uwaga: to jest bezpieczne dla wielu połączeń, utrwalone wartości last_insert_id lub mysql_insert_id (i być może mysqli_insert_id, nie sprawdziłem), są dla połączenia. Niesamowite!
Ryan S
11
Jest to ta sama metoda, co odpowiedź Salmana A, ale oto kod, którego naprawdę potrzebujesz, aby to zrobić.
Najpierw edytuj tabelę, aby automatycznie śledziła modyfikacje wiersza. Usuń ostatni wiersz, jeśli chcesz wiedzieć tylko, kiedy wiersz został pierwotnie wstawiony.
Ta metoda może pobrać nieprawidłowy identyfikator, jeśli drugie wstawianie jest wykonywane tuż po pierwszym zapytaniu wstawiania. Jeśli jednak użyjemy „WHERE” z tym zapytaniem, np. SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1 WHERE (niektóre warunki związane z ostatnim zapytaniem wstawiającym), to może to uniemożliwić pobranie niewłaściwego identyfikatora.
Naeem Ul Wahhab
1
@ TheNoble-Coder To prawda. Jeśli chcesz uzyskać identyfikator wiersza, który wpłynął na określone zapytanie aktualizujące, użyj techniki Pomyk. Ta technika jest bardziej przydatna, gdy jest używana asynchronicznie, gdy potrzebujesz tylko absolutnej ostatniej aktualizacji.
Więcej informacji na temat powyżej zaakceptowanej odpowiedzi Dla tych, którzy zastanawiali się nad :=&=
Istotna różnica między :=i =, która :=działa jako operator przypisania zmiennej wszędzie, podczas gdy =działa w ten sposób tylko w instrukcjach SET, a wszędzie indziej jest operatorem porównania.
Więc SELECT @var = 1 + 1;pozostawi @varniezmienione i zwróci wartość logiczną (1 lub 0 w zależności od bieżącej wartości @var), podczas gdy SELECT @var := 1 + 1;zmieni się @varna 2 i zwróci 2 .
[Źródło]
Hej dzięki. To, co mają na myśli, jest w rzeczywistości bardziej interesujące niż przyjęta powyżej odpowiedź.
Green
2
Hej, po prostu potrzebowałem takiej sztuczki - rozwiązałem to w inny sposób, może to zadziała. Należy pamiętać, że nie jest to rozwiązanie skalowalne i będzie bardzo niekorzystne w przypadku dużych zestawów danych.
Podziel zapytanie na dwie części -
najpierw wybierz identyfikatory wierszy, które chcesz zaktualizować, i zapisz je w tabeli tymczasowej.
po drugie, wykonaj oryginalną aktualizację ze stanem w instrukcji aktualizacji zmienionym na where id in temp_table.
Aby zapewnić współbieżność, musisz zablokować tabelę przed tymi dwoma krokami, a następnie zwolnić blokadę na końcu.
Ponownie, działa to dla mnie w przypadku zapytania, które kończy się na limit 1, więc nie używam nawet tabeli tymczasowej, ale zamiast tego po prostu zmienną do przechowywania wyniku pierwszej select.
Wolę tę metodę, ponieważ wiem, że zawsze będę aktualizować tylko jeden wiersz, a kod jest prosty.
Musiałem PRZESŁAĆ identyfikator (nie wiem dlaczego) ... lub nie mogę pobrać zawartości @uids (to była kropelka). Przy okazji wielkie dzięki za odpowiedź Pomyka!
Identyfikator ostatniego zaktualizowanego wiersza to ten sam identyfikator, którego używasz w zapytaniu „updateQuery”, aby znaleźć i zaktualizować ten wiersz. Więc po prostu zapisz (zadzwoń) ten identyfikator w dowolny sposób.
last_insert_id()zależy od AUTO_INCREMENT, ale ostatni zaktualizowany identyfikator nie.
Jeśli robisz tylko wstawki i chcesz mieć jedną z tej samej sesji, zrób zgodnie z odpowiedzią peirix. Jeśli dokonujesz modyfikacji, będziesz musiał zmodyfikować schemat bazy danych, aby przechowywać wpis, który był ostatnio aktualizowany.
Jeśli chcesz mieć identyfikator z ostatniej modyfikacji, która mogła pochodzić z innej sesji (tj. Nie tej, która została właśnie wykonana przez aktualnie działający kod PHP, ale wykonaną w odpowiedzi na inne żądanie), możesz dodać TIMESTAMP do tabeli o nazwie last_modified (więcej informacji można znaleźć pod adresem http://dev.mysql.com/doc/refman/5.1/en/datetime.html ), a następnie podczas aktualizacji ustaw last_modified = CURRENT_TIME.
Po ustawieniu tego możesz użyć zapytania takiego jak: SELECT id FROM table ORDER BY last_modified DESC LIMIT 1; aby pobrać ostatnio zmodyfikowany wiersz.
UPDATE foo WHERE bar = 1; SELECT id FROM foo WHERE bar = 1
?Odpowiedzi:
Znalazłem odpowiedź na ten problem :)
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;
EDYCJA przez aefxx
Technikę tę można dodatkowo rozszerzyć, aby pobrać identyfikator każdego wiersza, na który ma wpływ instrukcja aktualizacji:
SET @uids := null; UPDATE footable SET foo = 'bar' WHERE fooid > 5 AND ( SELECT @uids := CONCAT_WS(',', fooid, @uids) ); SELECT @uids;
Spowoduje to zwrócenie ciągu znaków ze wszystkimi identyfikatorami połączonymi przecinkami.
źródło
WHERE
klauzulę, możesz po prostu użyć tej samejWHERE
klauzuli w następnym zapytaniuSELECT id FROM footable WHERE fooid > 5
LAST_INSERT_ID()
może przyjąć argument, który ustawi wartość zwracaną przez następne wywołanie funkcjiLAST_INSERT_ID()
. Na przykład:UPDATE table SET id=LAST_INSERT_ID(id), row='value' WHERE other_row='blah';
. TerazSELECT LAST_INSERT_ID();
zwróci zaktualizowany identyfikator. Aby uzyskać więcej informacji, zobacz odpowiedź newtover.UPDATE lastinsertid_test SET row='value' WHERE row='asd' AND LAST_INSERT_ID(id) OR LAST_INSERT_ID(0);
. Jednak nie pobiera wielu identyfikatorów, więc ta odpowiedź jest lepsza.Hm, dziwię się, że wśród odpowiedzi nie widzę najłatwiejszego rozwiązania.
Załóżmy, że
item_id
jest to kolumna będąca liczbą całkowitą witems
tabeli i aktualizujesz wiersze za pomocą następującej instrukcji:UPDATE items SET qwe = 'qwe' WHERE asd = 'asd';
Następnie, aby poznać najnowszy wiersz, którego dotyczy problem, tuż po instrukcji, należy nieznacznie zaktualizować instrukcję do następującego:
UPDATE items SET qwe = 'qwe', item_id=LAST_INSERT_ID(item_id) WHERE asd = 'asd'; SELECT LAST_INSERT_ID();
Jeśli chcesz zaktualizować tylko naprawdę zmieniony wiersz, musisz dodać warunkową aktualizację item_id poprzez LAST_INSERT_ID sprawdzając, czy dane zmienią się w wierszu.
źródło
UPDATE items SET qwe = 'qwe' WHERE asd = 'asd' AND LAST_INSERT_ID(item_id); SELECT LAST_INSERT_ID();
Jest to oficjalnie proste, ale niezwykle sprzeczne z intuicją. Jeśli robisz:
update users set status = 'processing' where status = 'pending' limit 1
Zmień to na:
update users set status = 'processing' where status = 'pending' and last_insert_id(user_id) limit 1
Dodanie
last_insert_id(user_id)
wwhere
klauzuli mówi MySQL, aby ustawić swoją wewnętrzną zmienną na identyfikator znalezionego wiersza. Kiedy przekazujesz taką wartośćlast_insert_id(expr)
, w końcu zwraca tę wartość, która w przypadku identyfikatorów takich jak tutaj jest zawsze dodatnią liczbą całkowitą i dlatego zawsze zwraca wartość true, nigdy nie kolidując z klauzulą where. Działa to tylko wtedy, gdy rzeczywiście znaleziono jakiś wiersz, więc pamiętaj, aby sprawdzić wiersze, których dotyczy problem. Następnie możesz uzyskać identyfikator na wiele sposobów.MySQL
last_insert_id()
MySQL
mysql_insert_id()
PHP
mysqli_insert_id()
Kładąc wszystko razem:
$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(); }
(FYI, że klasa DB jest tutaj .)
źródło
Jest to ta sama metoda, co odpowiedź Salmana A, ale oto kod, którego naprawdę potrzebujesz, aby to zrobić.
Najpierw edytuj tabelę, aby automatycznie śledziła modyfikacje wiersza. Usuń ostatni wiersz, jeśli chcesz wiedzieć tylko, kiedy wiersz został pierwotnie wstawiony.
ALTER TABLE mytable ADD lastmodified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
Następnie, aby znaleźć ostatni zaktualizowany wiersz, możesz użyć tego kodu.
SELECT id FROM mytable ORDER BY lastmodified DESC LIMIT 1;
Cały ten kod pochodzi z MySQL vs PostgreSQL: Dodanie kolumny „Last Modified Time” do tabeli i MySQL Manual: Sorting Rows . Właśnie go złożyłem.
źródło
Zapytanie:
$sqlQuery = "UPDATE update_table SET set_name = 'value' WHERE where_name = 'name' LIMIT 1;";
Funkcja PHP:
function updateAndGetId($sqlQuery) { mysql_query(str_replace("SET", "SET id = LAST_INSERT_ID(id),", $sqlQuery)); return mysql_insert_id(); }
To dla mnie praca;)
źródło
Więcej informacji na temat powyżej zaakceptowanej odpowiedzi
Dla tych, którzy zastanawiali się nad
:=
&=
Istotna różnica między
:=
i=
, która:=
działa jako operator przypisania zmiennej wszędzie, podczas gdy=
działa w ten sposób tylko w instrukcjach SET, a wszędzie indziej jest operatorem porównania.Więc
SELECT @var = 1 + 1;
pozostawi@var
niezmienione i zwróci wartość logiczną (1 lub 0 w zależności od bieżącej wartości @var), podczas gdySELECT @var := 1 + 1;
zmieni się@var
na 2 i zwróci 2 . [Źródło]źródło
Hej, po prostu potrzebowałem takiej sztuczki - rozwiązałem to w inny sposób, może to zadziała. Należy pamiętać, że nie jest to rozwiązanie skalowalne i będzie bardzo niekorzystne w przypadku dużych zestawów danych.
Podziel zapytanie na dwie części -
najpierw wybierz identyfikatory wierszy, które chcesz zaktualizować, i zapisz je w tabeli tymczasowej.
po drugie, wykonaj oryginalną aktualizację ze stanem w instrukcji aktualizacji zmienionym na
where id in temp_table
.Aby zapewnić współbieżność, musisz zablokować tabelę przed tymi dwoma krokami, a następnie zwolnić blokadę na końcu.
Ponownie, działa to dla mnie w przypadku zapytania, które kończy się na
limit 1
, więc nie używam nawet tabeli tymczasowej, ale zamiast tego po prostu zmienną do przechowywania wyniku pierwszejselect
.Wolę tę metodę, ponieważ wiem, że zawsze będę aktualizować tylko jeden wiersz, a kod jest prosty.
źródło
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;
Musiałem PRZESŁAĆ identyfikator (nie wiem dlaczego) ... lub nie mogę pobrać zawartości @uids (to była kropelka). Przy okazji wielkie dzięki za odpowiedź Pomyka!
źródło
Identyfikator ostatniego zaktualizowanego wiersza to ten sam identyfikator, którego używasz w zapytaniu „updateQuery”, aby znaleźć i zaktualizować ten wiersz. Więc po prostu zapisz (zadzwoń) ten identyfikator w dowolny sposób.
last_insert_id()
zależy odAUTO_INCREMENT
, ale ostatni zaktualizowany identyfikator nie.źródło
Moje rozwiązanie jest takie, że najpierw wybierz "id" (@uids) za pomocą polecenia select, a po zaktualizowaniu tego identyfikatora za pomocą @uids.
SET @uids := (SELECT id FROM table WHERE some = 0 LIMIT 1); UPDATE table SET col = 1 WHERE id = @uids;SELECT @uids;
zadziałało przy moim projekcie.
źródło
Jeśli robisz tylko wstawki i chcesz mieć jedną z tej samej sesji, zrób zgodnie z odpowiedzią peirix. Jeśli dokonujesz modyfikacji, będziesz musiał zmodyfikować schemat bazy danych, aby przechowywać wpis, który był ostatnio aktualizowany.
Jeśli chcesz mieć identyfikator z ostatniej modyfikacji, która mogła pochodzić z innej sesji (tj. Nie tej, która została właśnie wykonana przez aktualnie działający kod PHP, ale wykonaną w odpowiedzi na inne żądanie), możesz dodać TIMESTAMP do tabeli o nazwie last_modified (więcej informacji można znaleźć pod adresem http://dev.mysql.com/doc/refman/5.1/en/datetime.html ), a następnie podczas aktualizacji ustaw last_modified = CURRENT_TIME.
Po ustawieniu tego możesz użyć zapytania takiego jak: SELECT id FROM table ORDER BY last_modified DESC LIMIT 1; aby pobrać ostatnio zmodyfikowany wiersz.
źródło
Nie ma potrzeby używania tak długiego kodu MySQL. W PHP zapytanie powinno wyglądać mniej więcej tak:
$updateQuery = mysql_query("UPDATE table_name SET row='value' WHERE id='$id'") or die ('Error'); $lastUpdatedId = mysql_insert_id();
źródło