MySQL - ZAKTUALIZUJ wiele wierszy z różnymi wartościami w jednym zapytaniu

139

Próbuję zrozumieć, jak ZAKTUALIZOWAĆ wiele wierszy z różnymi wartościami i po prostu tego nie rozumiem. Rozwiązanie jest wszędzie, ale wydaje mi się trudne do zrozumienia.

Na przykład trzy aktualizacje do 1 zapytania:

UPDATE table_users
SET cod_user = '622057'
    , date = '12082014'
WHERE user_rol = 'student'
    AND cod_office = '17389551'; 

UPDATE table_users
SET cod_user = '2913659'
    , date = '12082014'
WHERE user_rol = 'assistant'
    AND cod_office = '17389551'; 

UPDATE table_users
SET cod_user = '6160230'
    , date = '12082014'
WHERE user_rol = 'admin'
    AND cod_office = '17389551'; 

I czytać przykład, ale ja naprawdę nie rozumiem, jak zrobić kwerendę. to znaczy:

UPDATE table_to_update
SET cod_user= IF(cod_office = '17389551','622057','2913659','6160230')
    ,date = IF(cod_office = '17389551','12082014')
WHERE ?? IN (??) ;

Nie jestem do końca jasne, jak wykonać zapytanie, jeśli w warunku GDZIE i warunek JEŻELI występuje wiele warunków… wszelkie pomysły?

franvergara66
źródło
Czy to odpowiada na twoje pytanie? Wiele aktualizacji w MySQL
PeterPan666

Odpowiedzi:

188

Możesz to zrobić w ten sposób:

UPDATE table_users
    SET cod_user = (case when user_role = 'student' then '622057'
                         when user_role = 'assistant' then '2913659'
                         when user_role = 'admin' then '6160230'
                    end),
        date = '12082014'
    WHERE user_role in ('student', 'assistant', 'admin') AND
          cod_office = '17389551';

Nie rozumiem twojego formatu daty. Daty powinny być przechowywane w bazie danych przy użyciu natywnych typów daty i czasu.

Gordon Linoff
źródło
jak mogę to zrobić, aby aktualizacja została wykonana, jeśli rekord już istnieje
franvergara66
1
@ franvergara66. . . Nie rozumiem twojego komentarza. updatewpływa tylko na rekordy, które już istnieją.
Gordon Linoff,
Przepraszam pana angielskiego, kiedy próbuję zaktualizować mysql, daj mi błąd: # 1062 - Zduplikowany wpis „XXX” dla klucza „PRIMARY”. Dzieje się tak, gdy próbuję zaktualizować rekord o tę samą wartość, którą już miał, czy istnieje sposób na pominięcie aktualizacji, jeśli bieżąca wartość jest taka sama, jak w przypadku aktualizacji?
franvergara66,
1
@ franvergara66. . . Możesz mieć inny problem. Jeśli cod_userjest to klucz podstawowy, a wartości są tasowane, prawdopodobnie najlepszym rozwiązaniem jest wielokrotne aktualizacje.
Gordon Linoff,
1
tak, widzę, prawdziwy problem polega na tym, że jest kilku asystentów, a następnie podczas próby aktualizacji naruszana jest integralność klucza podstawowego. Dziękuję Ci bardzo za Twój czas.
franvergara66,
108

MySQL umożliwia bardziej czytelny sposób łączenia wielu aktualizacji w jedno zapytanie. Wydaje się, że lepiej pasuje do opisywanego przez ciebie scenariusza, jest znacznie łatwiejszy do odczytania i pozwala uniknąć tych trudnych do rozplątania wielu warunków.

INSERT INTO table_users (cod_user, date, user_rol, cod_office)
VALUES
('622057', '12082014', 'student', '17389551'),
('2913659', '12082014', 'assistant','17389551'),
('6160230', '12082014', 'admin', '17389551')
ON DUPLICATE KEY UPDATE
 cod_user=VALUES(cod_user), date=VALUES(date)

Zakłada się, że user_rol, cod_officekombinacja jest kluczem podstawowym. Jeśli tylko jedno z nich jest kluczem podstawowym , dodaj drugie pole do listy UPDATE. Jeśli żaden z nich nie jest kluczem podstawowym (co wydaje się mało prawdopodobne), to podejście zawsze tworzy nowe rekordy - prawdopodobnie nie to, co jest pożądane.

Jednak takie podejście sprawia, że ​​przygotowane zestawienia są łatwiejsze do zbudowania i bardziej zwięzłe.

Trevedhek
źródło
4
Dziękuję Ci! To jest to, czego szukałem przez długi czas, najczystszy sposób, nie mogłem cod_user=VALUES(cod_user), ...
rozgryźć
18
Uwaga: spowoduje to dodanie nowych wierszy, jeśli klucz nie istnieje w tabeli, co spowoduje niepożądane rekordy.
Faraz
1
Trudne w użyciu nigdy nie wkładanego IODKU, ale bardzo eleganckie.
Tom Desp
Należy pamiętać, że to podejście wymaga ustawienia klucza podstawowego dla tabeli.
FlameStorm
5
To nie zadziała, jeśli pominiesz kolumny, które nie mogą mieć wartości NULL, ponieważ sql nadal próbuje utworzyć nowy rekord, zanim faktycznie skorzysta z aktualizacji.
Arno van Oordt
15

Możesz użyć CASEinstrukcji do obsługi wielu scenariuszy jeśli / to:

UPDATE table_to_update 
SET  cod_user= CASE WHEN user_rol = 'student' THEN '622057'
                   WHEN user_rol = 'assistant' THEN '2913659'
                   WHEN user_rol = 'admin' THEN '6160230'
               END
    ,date = '12082014'
WHERE user_rol IN ('student','assistant','admin')
  AND cod_office = '17389551';
Hart CO
źródło
1
Zrobiłeś literówkę na końcu instrukcji CASE: masz 2 przecinki obok siebie.
pmrotule
8
update table_name
set cod_user = 
    CASE 
    WHEN user_rol = 'student' THEN '622057'
    WHEN user_rol = 'assistant' THEN '2913659'
    WHEN user_rol = 'admin' THEN '6160230'?
    END,date = '12082014'

WHERE user_rol IN ('student','assistant','admin')
AND cod_office = '17389551';
Akshay Bhan
źródło
0

Aby przedłużyć odpowiedź na @Trevedhek ,

W przypadku, gdy aktualizacja musi być wykonana przy użyciu nieunikalnych kluczy, potrzebne będą 4 zapytania

UWAGA: To nie jest bezpieczne dla transakcji

Można to zrobić za pomocą tabeli tymczasowej.

Krok 1: Utwórz klucze tabeli tymczasowej i kolumny, które chcesz zaktualizować

CREATE TEMPORARY TABLE  temp_table_users
(
    cod_user varchar(50)
    , date varchar(50)
    , user_rol varchar(50)
    ,  cod_office varchar(50)
) ENGINE=MEMORY

Krok 2: Wstaw wartości do tabeli tymczasowej

Krok 3: Zaktualizuj oryginalną tabelę

UPDATE table_users t1
JOIN temp_table_users tt1 using(user_rol,cod_office)
SET 
t1.cod_office = tt1.cod_office
t1.date = tt1.date

Krok 4: Usuń tabelę tymczasową

Sab
źródło
0
UPDATE Table1 SET col1= col2 FROM (SELECT col2, col3 FROM Table2) as newTbl WHERE col4= col3

Tutaj col4 i col1 są w Table1. col2 i col3 znajdują się w Table2
Próbuję zaktualizować każdy col1, gdzie col4 = col3 różne wartości dla każdego wiersza

ankit giri
źródło
-1

Zrobiłem to w ten sposób:

<update id="updateSettings" parameterType="PushSettings">
    <foreach collection="settings" item="setting">
        UPDATE push_setting SET status = #{setting.status}
        WHERE type = #{setting.type} AND user_id = #{userId};
    </foreach>
</update>

gdzie PushSettings jest

public class PushSettings {

    private List<PushSetting> settings;
    private String userId;
}

to działa dobrze

ru51an
źródło
autor chce 1 zapytanie, jasne jest, że może to zrobić z każdym, co spowoduje kilka zapytań
Hristo93