MySQL - ATUALIZE várias linhas com valores diferentes em uma consulta

139

Estou tentando entender como atualizar várias linhas com valores diferentes e simplesmente não entendi. A solução está em toda parte, mas para mim parece difícil de entender.

Por exemplo, três atualizações em uma consulta:

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'; 

Eu li um exemplo, mas realmente não entendo como fazer a consulta. ou seja:

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

Não estou totalmente claro como fazer a consulta se houver várias condições na condição WHERE e IF se ... alguma idéia?

franvergara66
fonte
Isso responde sua pergunta? Várias atualizações no MySQL
PeterPan666

Respostas:

188

Você pode fazer assim:

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';

Não entendo o seu formato de data. As datas devem ser armazenadas no banco de dados usando tipos de data e hora nativos.

Gordon Linoff
fonte
como posso fazer para que a atualização é executado, se o registro já existe
franvergara66
1
@ franvergara66. . . Eu não entendo o seu comentário. updates afetam apenas registros que já existem.
Gordon Linoff
Com licença meu senhor inglês, quando tento fazer uma atualização do mysql me dá o erro: # 1062 - Entrada duplicada 'XXX' para a chave 'PRIMARY'. Isso ocorre quando tento atualizar um registro com o mesmo valor que já possuía, existe alguma maneira de ignorar a atualização se o valor atual for o mesmo que está sendo atualizado?
franvergara66
1
@ franvergara66. . . Você pode ter um problema diferente. Se cod_userfor uma chave primária e os valores estiverem sendo embaralhados, várias atualizações provavelmente serão a melhor rota.
Gordon Linoff
1
Sim, entendo, o verdadeiro problema é que existem vários assistentes. Ao tentar fazer uma atualização, a integridade da chave primária é violada. Muito obrigado pelo seu tempo.
franvergara66
109

O MySQL permite uma maneira mais legível de combinar várias atualizações em uma única consulta. Isso parece se encaixar melhor no cenário que você descreve, é muito mais fácil de ler e evita essas múltiplas condições difíceis de desembaraçar.

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)

Isso pressupõe que a user_rol, cod_officecombinação seja uma chave primária. Se apenas uma delas for a chave primária , adicione o outro campo à lista UPDATE. Se nenhum deles for uma chave primária (que parece improvável), essa abordagem sempre criará novos registros - provavelmente não o que se deseja.

No entanto, essa abordagem facilita a criação de declarações preparadas e é mais concisa.

Trevedhek
fonte
4
Obrigado! Isto é o que eu estava procurando por um longo tempo, a forma mais limpa olhando, eu não conseguia descobrir essa sintaxe, especificamente cod_user=VALUES(cod_user), ..., mesmo a partir oficiais MySQL 5.6 docs
Yuriy Dyachkov
18
Nota: Isso adicionará novas linhas se a chave não existir na tabela, resultando em registros indesejados.
Faraz
1
Difícil de usar um IODKU nunca inserido, mas muito elegante.
Tom Desp
E observe que essa abordagem exige que a chave primária esteja definida para a tabela.
FlameStorm 6/09
5
Isso não funcionará se você omitir colunas que não possam ser nulas, pois o sql ainda tenta criar um novo registro antes de recorrer à atualização.
Arno van Oordt
15

Você pode usar uma CASEinstrução para manipular vários cenários if / then:

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
fonte
1
Você digitou um erro de digitação no final da instrução CASE: possui duas vírgulas uma ao lado da outra.
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
fonte
0

Para estender a resposta @Trevedhek ,

Caso a atualização precise ser feita com chaves não exclusivas, serão necessárias 4 consultas

NOTA: Isso não é seguro para transações

Isso pode ser feito usando uma tabela temporária.

Etapa 1: Crie as chaves da tabela temporária e as colunas que você deseja atualizar

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

Etapa 2: Inserir os valores na tabela temporária

Etapa 3: atualizar a tabela original

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

Etapa 4: Soltar a tabela temporária

Sab
fonte
0
UPDATE Table1 SET col1= col2 FROM (SELECT col2, col3 FROM Table2) as newTbl WHERE col4= col3

Aqui col4 e col1 estão na Tabela1. col2 e col3 estão na Tabela2
Estou tentando atualizar cada col1 onde col4 = col3 valor diferente para cada linha

ankit giri
fonte
-1

Eu fiz assim:

<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>

onde PushSettings é

public class PushSettings {

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

Funciona bem

ru51an
fonte
autor quer 1 consulta, é claro que ele pode fazê-lo com foreach, o que fará várias consultas
Hristo93 16/06