2009-04-22 10 views
104

Mam następujące zapytanie:MySQL ON DUPLICATE KEY - last insert id?

INSERT INTO table (a) VALUES (0) 
    ON DUPLICATE KEY UPDATE a=1 

chcę identyfikator albo wkładki lub aktualizacji. Zwykle uruchamiam drugie zapytanie w celu uzyskania tego, ponieważ uważam, że parametr insert_id() zwraca tylko "wstawiony" identyfikator, a nie zaktualizowany identyfikator.

Czy istnieje sposób INSERT/UPDATE i pobranie identyfikatora wiersza bez uruchamiania dwóch zapytań?

+3

Zamiast przypuszczać, dlaczego sam tego nie przetestujesz? Kod SQL w powyższej edycji działa, a dzięki moim testom jest szybszy niż przechwycenie niepowodzenia wstawiania, użycie INSERT IGNORE lub wybranie, aby sprawdzić, czy istnieje pierwszy duplikat. –

+1

OSTRZEŻENIE: Proponowane rozwiązanie działa, ale wartość auto_Inrement zwiększa się, nawet jeśli nie ma wkładki. Jeśli zduplikowany klucz zdarza się często, możesz chcieć uruchomić 'alter table tablename AUTO_INCREMENT = 0;' po powyższym zapytaniu, aby uniknąć dużych luk w twoich wartościach id. –

Odpowiedz

125

Odjazd tej strony: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
na dole strony wyjaśniają w jaki sposób można dokonać LAST_INSERT_ID znaczące aktualizacje przekazując wyrażenie do th w funkcji MySQL.

z dokumentacji np MySQL:

Jeśli tabela zawiera kolumny AUTO_INCREMENT i INSERT ... UPDATE wstawia wiersz, LAST_INSERT_ID() zwraca wartość AUTO_INCREMENT. Jeśli instrukcja aktualizuje wiersz, funkcja LAST_INSERT_ID() nie ma znaczenia. Można jednak obejść ten problem, używając LAST_INSERT_ID (wyrażenie). Załóżmy, że id to kolumna AUTO_INCREMENT. Aby LAST_INSERT_ID() znaczące aktualizacje, wiersze wkładka następująco:

INSERT INTO table (a,b,c) VALUES (1,2,3) 
    ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3; 
+2

Jakoś tęskniłem za tym, patrząc na tę stronę. Część aktualizacji wygląda następująco: ID UPDATE = LAST_INSERT_ID (identyfikator) To działa świetnie. Dzięki! – thekevinscott

+1

Cieszę się, że mogę pomóc! – fredrik

+6

Podobno funkcja php mysql_insert_id() zwraca poprawną wartość w obu przypadkach: http://www.php.net/manual/en/function.mysql-insert-id.php#59718. – jayarjo

2

Możesz spojrzeć na REPLACE, które jest zasadniczo usuwanie/wstawić, jeśli rekord istnieje. Ale to zmieniłoby pole auto increment, jeśli jest obecne, co może przerwać relacje z innymi danymi.

+1

Ach tak - szukam czegoś, co nie pozbyłoby się wcześniejszego identyfikatora – thekevinscott

+0

Może to być niebezpieczne także dlatego, że może to również spowodować usunięcie innych powiązanych danych (przez ograniczenia). – Serge

0

Warto zauważyć, i może to być oczywiste (ale powiem to i tak dla jasności tutaj), które zastępują będzie zdmuchnąć istniejący pasujący wiersz przed wstawieniem nowych danych. ON DUPLICATE KEY UPDATE zaktualizuje tylko określone kolumny i zachowa wiersz.

Z manual:

REPLACE działa dokładnie tak jak INSERT, wyjątkiem tego, że jeśli stary wiersz w tabeli ma taką samą wartość jak nowy wiersz dla PRIMARY KEY lub indeksu unikalne, stary wiersz jest usuwany przed wstawieniem nowego wiersza .

25

Aby być dokładnym, jeśli jest to oryginalna zapytania:

INSERT INTO table (a) VALUES (0) 
ON DUPLICATE KEY UPDATE a=1 

i „id” jest kluczem podstawowym automatycznego przyrostu niż byłoby to roztwór roboczy:

INSERT INTO table (a) VALUES (0) 
    ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1 

Wszystko tutaj: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Jeśli tabela zawiera AUTO_INCREMENT kolumna i INSERT ... UPDATE wstawia wiersz, funkcja LAST_INSERT_ID() zwraca wartość AUTO_INCREMENT. Jeśli instrukcja aktualizuje wiersz zamiast, LAST_INSERT_ID() nie ma znaczenia. Można jednak obejść ten za pomocą LAST_INSERT_ID (wyrażenie). Załóżmy, że id to kolumna AUTO_INCREMENT .

+3

Tak, zobacz zaakceptowaną odpowiedź na to, co powiedziałeś. Nie trzeba ożywiać 3-letnich postów. Dzięki za twój wysiłek. – fancyPants

+1

@tombom Jedynym powodem, dla którego wysłałem tę odpowiedź, jest to, że zaakceptowana odpowiedź jest nieprawidłowa - nie zadziała, jeśli nie będzie nic do aktualizacji. –

+0

+1 chociaż myślę, że zaakceptowana odpowiedź wspomina: :) – fancyPants

0

Istniejące rozwiązania działają, jeśli używa się autoinkrementacji. Mam sytuację, w której użytkownik może zdefiniować prefiks i powinien ponownie uruchomić sekwencję na 3000. Z powodu tego zróżnicowanego prefiksu, nie mogę użyć autoinkrementacji, co powoduje, że last_insert_id jest puste dla insertów. Rozwiązałem go z następujących czynności:

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1); 
SELECT LAST_INSERT_ID(); 

Jeśli prefiks istnieje, to będzie ją zwiększyć i wypełnić last_insert_id. Jeśli prefiks nie istnieje, wstawi prefiks o wartości 3000 i wypełni last_insert_id wartością 3000.

Powiązane problemy