Wstaw do tabeli MySQL lub zaktualizuj, jeśli istnieje

875

Chcę dodać wiersz do tabeli bazy danych, ale jeśli istnieje wiersz z tym samym unikalnym kluczem, chcę go zaktualizować.

Na przykład:

insert into table (id, name, age) values(1, "A", 19)

Powiedzmy, że unikalny klucz to id, aw mojej bazie danych jest wiersz z id = 1. W takim przypadku chcę zaktualizować ten wiersz o te wartości. Zwykle daje to błąd.
Jeśli insert IGNOREgo użyję, zignoruje błąd, ale nadal się nie aktualizuje.

Keshan
źródło
5
SQL wymaga oficjalnej składni dla tego przypadku użycia, który nie wymusza powielania wartości w składni i zachowuje klucz podstawowy.
Pete Alvin
Aby uzyskać wpływ identyfikatora, zapoznaj się z MySQL NA DUPLICATE KEY - identyfikator ostatniej wstawki?
Kris Roofe
Uwaga: od wersji 5.7 to podejście nie obsługuje bezpośrednio klauzuli WHERE w ramach operacji INSERT / UPDATE. Również AKTUALIZACJA faktycznie liczy się jako dwie osobne operacje (USUŃ i WSTAW) ... w przypadku, gdy ma to znaczenie dla celów kontroli. (Learnbit)
dreftymac,

Odpowiedzi:

1599

Posługiwać się INSERT ... ON DUPLICATE KEY UPDATE

PYTANIE:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19
Donnie
źródło
86
+1 Z tego, co znalazłem, ta metoda jest mniej problematyczna dla kluczy z auto-przyrostem i innych unikatowych kolizji kluczy niż WYMIANA NA, i jest bardziej wydajna.
Andrew Ensley,
46
Wiem, że wszyscy nawiązujecie do tego, ale chcę być wyraźny w stosunku do innych. Jeśli wstawiony identyfikator NIE JEST KLUCZEM PODSTAWOWYM lub UNIKALNYM, to nie zadziała. Początkowo to nie działało, ponieważ mój identyfikator nie był unikalny.
Keven,
7
Zastanawiam się, dlaczego affected row countwyniki 2przy udanej aktualizacji (na duplikacie klucza) pojedynczego wiersza? Czy ktoś jeszcze miał taki wynik? (Dane są aktualizowane poprawnie: co oznacza, że ​​aktualizowany jest tylko 1 wiersz)
Dimitry K
14
Jest to trochę za późno, ale tak czy inaczej: w instrukcji podano, że aktualizacje ON DUPLICATE KEY UPDATEzwiększają dotknięte wiersze o 2. Zgłasza 0, jeśli nic nie jest faktycznie aktualizowane (tak jak zwykłe UPDATE).
Vatev
61
Zauważ też, że możesz użyć WARTOŚCI (nazwa), aby odwołać się do wartości, którą próbujesz wstawić, np. WSTAWIĆ DO tabeli (identyfikator, imię, wiek) WARTOŚCI (1, „A”, 19) NA DUPLIKACIE KLUCZOWA AKTUALIZACJA nazwa = WARTOŚCI (nazwa) , wiek = WARTOŚCI (wiek)
Ciekawy Sam
246

Sprawdź WYMIANA

http://dev.mysql.com/doc/refman/5.0/en/replace.html

REPLACE into table (id, name, age) values(1, "A", 19)
Martin Schapendonk
źródło
11
@Piontek Ponieważ ten jest krótszy i łatwiejszy do zrozumienia i nikt nie wyjaśnił, dlaczego „wstaw na duplikacie” jest lepsze.
Mr_Chimp
77
zmienia identyfikatory rekordu, a tym samym może zniszczyć zagraniczne odniesienia.
boh
102
Innym problemem związanym z REPLACE INTO jest to, że musisz określić wartości WSZYSTKICH pól ... w przeciwnym razie pola zostaną utracone lub zastąpione wartościami domyślnymi. REPLACE INTO zasadniczo usuwa wiersz, jeśli istnieje, i wstawia nowy wiersz. W tym przykładzie, jeśli zrobiłeś 'WYMIENIĆ W tabeli wartości (id, wiek) (1, 19), wówczas pole nazwy stałoby się puste.
Dale,
33
To jest faktycznie USUŃ cały wiersz i wykonaj nowy WSTAW.
mjb
8
@mjb Dlatego musisz mieć uprawnienia USUŃ, których najlepiej nie mieć, jeśli ich nie potrzebujesz. Użytkownik bazy danych mojego środowiska ma tylko uprawnienia INSERT i UPDATE, więc REPLACE nie będzie działać.
ndm13
54

Podczas korzystania z wstawiania wsadowego użyj następującej składni:

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...
Fabiano Souza
źródło
Bardzo przydatne, jeśli chcesz manipulować nową wartością
Hunger
Jeśli VALUES(name)to nie pomoże, możesz spróbowaćname = 'name_value',...;
Son Pham
26

Wypróbuj to:

INSERT INTO table (id, name, age) VALUES (1, 'A', 19) ON DUPLICATE KEY UPDATE id = id + 1;

Mam nadzieję że to pomoże.

Luis Reyes
źródło
6
właściwie nie muszę dodawać nowych wartości do innego wiersza z nowym identyfikatorem, zamiast tego chcę zastąpić istniejące wartości id = 1 tymi wartościami. (jak rozumiem, zwiększa to identyfikator i dodaje dane)
Keshan,
49
Nie sądzę, że chce zwiększyć identyfikator o jeden na duplikatach.
Donnie
7
„transgress” nie jest słowem, którego szukasz :) Niestety, teraz widziałem „transgress”, nie mogę już wizualizować rzeczywistego słowa ..
mwfearnley 13.04.17
1
Czy szukałeś „trawersów” lub „okładek”?
Chris Dev
4
@mwfearnley Słowo, które próbujesz sobie wyobrazić, to „wykracza poza”. Zajęło mi to tylko półtora roku :-)
Michael Krebs
20

Spróbuj tego:

INSERT INTO table (id,name,age) VALUES('1','Mohammad','21') ON DUPLICATE KEY UPDATE name='Mohammad',age='21'

Uwaga:
Jeśli id ​​jest kluczem podstawowym, to po pierwszym wstawieniu za id='1'każdym razem, gdy próba wstawienia id='1'zaktualizuje imię i wiek, a poprzednie imię i nazwisko zmienią się.

Rasel
źródło
Chcę pracować bez użycia identyfikatora . Próbowałeś bez klucza podstawowego?
ersks
@ersks zobacz pytanie. użytkownik zapytał, kiedy jest unikalny klucz
Rasel
Rozumiem, ale staram się rozwiązać problem, w którym znane są tylko te wartości. Tak więc w takiej sytuacji napisałem powyżej komentarz z nadzieją na prawidłowe rozwiązanie.
ersks
15
INSERT IGNORE INTO table (id, name, age) VALUES (1, "A", 19);

INSERT INTO TABLE (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE NAME = "A", AGE = 19;

REPLACE INTO table (id, name, age) VALUES(1, "A", 19);

Wszystkie te rozwiązania będą działać w odniesieniu do twojego pytania.

Jeśli chcesz poznać szczegóły dotyczące tego oświadczenia, odwiedź ten link

Dilraj Singh
źródło
REPLACEnie jest udokumentowany w połączonym dokumencie.
Ray Baxter,
zapytania SQL pełne literówek, twoje przykłady nie będą działać. WSTAWIĆ DO TABELI (nie DO TABELI) I NA DUPLIKACJĘ KLUCZOWEJ AKTUALIZACJI (nie NA ZESTAWIE AKTUALIZACJI DUPLIKATU). Nie jestem pewien, kto to poprze
Robert Sinclair,
1
Przepraszamy za błąd literówki. Dzięki za poprawienie mnie
Dilraj Singh,
11

Podczas korzystania z SQLite:

REPLACE into table (id, name, age) values(1, "A", 19)

Pod warunkiem, że idjest to klucz podstawowy. Albo po prostu wstawia kolejny wiersz. Zobacz INSERT (SQLite).

DawnSong
źródło
Co replace intoto jest dokładnie „wstawić lub zaktualizować, gdy istnieje”. @Owl
DawnSong
+1 (1 z 3) Przekonałem się, że to działa w mojej sytuacji - musiałem zastąpić istniejący wiersz unikalnym kluczem, a jeśli nie, to dodaj wiersz. Najprostsze rozwiązania tutaj.
therobyouknow
(2 z 3) Moje zapytanie:CREATE TRIGGER worklog_update AFTER INSERT ON worklog FOR EACH ROW REPLACE INTO support_time_monthly_hours ( ProjectID, monthTotalTime, Year, Month ) SELECT jiraissue.PROJECT, SUM(worklog.timeworked), YEAR(CURRENT_DATE()), MONTH(CURRENT_DATE()) FROM worklog, jiraissue WHERE worklog.issueid = jiraissue.ID AND jiraissue.PROJECT = (SELECT PROJECT FROM jiraissue WHERE NEW.issueid = jiraissue.ID ) AND worklog.startdate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00') AND NOW();
therobyouknow 30.01.2017
(3 z 3) Powiązane pytanie / odpowiedź stackoverflow.com/questions/41767517/…
therobyouknow 30.01.2017
2
Problem z tym w mysql polega na tym, że zamiana usunie inne wartości, jeśli nie zostaną podane. Jednak rozwiązanie @ fabiano-souza jest bardziej odpowiednie
Quamber Ali
11

Tylko dlatego, że szukałem tego rozwiązania, ale do aktualizacji z innej tabeli o identycznej strukturze (w moim przypadku strona testuje DB na DB):

INSERT  live-db.table1
SELECT  *
FROM    test-db.table1 t
ON DUPLICATE KEY UPDATE
        ColToUpdate1 = t.ColToUpdate1,
        ColToUpdate2 = t.ColToUpdate2,
        ...

Jak wspomniano w innym miejscu, należy uwzględnić tylko kolumny, które chcesz zaktualizować ON DUPLICATE KEY UPDATE.

Nie trzeba wymieniać kolumn w INSERTlub SELECT, choć zgadzam się, że to prawdopodobnie lepsza praktyka.

SteveCinq
źródło
4

Jeśli chcesz utworzyć non-primarypola jako kryteria / warunki ON DUPLICATE, możesz utworzyć UNIQUE INDEXklucz w tej tabeli, aby je uruchomić DUPLICATE.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`);

A jeśli chcesz połączyć dwa pola, aby uczynić go unikalnym w tabeli, możesz to osiągnąć, dodając więcej do ostatniego parametru.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`, `age`);

Uwaga: pamiętaj, aby najpierw usunąć wszystkie dane, które mają takie same namei agewartości w innych wierszach.

DELETE table FROM table AS a, table AS b WHERE a.id < b.id 
AND a.name <=> b.name AND a.age <=> b.age;

Następnie powinno uruchomić ON DUPLICATEzdarzenie.

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name = VALUES(name), age = VALUES(age)
Bogaty
źródło
2

W moim przypadku utworzyłem poniższe zapytania, ale w pierwszym zapytaniu, jeśli id1 już istnieje, a wiek już tam jest, po tym, jeśli utworzysz pierwsze zapytanie bez, agewówczas wartość nie agebędzie równa

REPLACE into table SET `id` = 1, `name` = 'A', `age` = 19

w celu uniknięcia powyższego problemu utwórz zapytanie jak poniżej

INSERT INTO table SET `id` = '1', `name` = 'A', `age` = 19 ON DUPLICATE KEY UPDATE `id` = "1", `name` = "A",`age` = 19

niech ci to pomoże ...

Renish Gotecha
źródło
2
Czy ktoś wie, dlaczego musimy przypisać wartości dwa razy? Dlaczego MySQL nie pozwala nam zakończyć zapytania o ON DUPLICATE KEY UPDATE bez powielania wszystkich instrukcji przypisania? Niektóre tabele bazy danych mają wiele kolumn, co wydaje się zbędne / nieuzasadnione. Rozumiem, dlaczego mamy opcję alternatywnych przydziałów, ale dlaczego nie mamy także opcji ich pominięcia? Ciekawe, czy ktoś wie.
Blue Water
2

W przypadku, gdy chcesz zachować stare pole (np. Nazwa). Zapytanie będzie:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
Xman Classical
źródło