Eu sei que você pode inserir várias linhas ao mesmo tempo, existe uma maneira de atualizar várias linhas ao mesmo tempo (como em uma consulta) no MySQL?
Editar: Por exemplo, tenho o seguinte
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
Quero combinar todas as atualizações a seguir em uma consulta
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
mysql
sql
sql-update
Teifion
fonte
fonte
Como você possui valores dinâmicos, é necessário usar um IF ou CASE para que as colunas sejam atualizadas. Fica meio feio, mas deve funcionar.
Usando seu exemplo, você pode fazê-lo como:
fonte
$commandTxt = 'UPDATE operations SET chunk_finished = CASE id '; foreach ($blockOperationChecked as $operationID => $operationChecked) $commandTxt .= " WHEN $operationID THEN $operationChecked "; $commandTxt .= 'ELSE id END WHERE id IN ('.implode(', ', array_keys(blockOperationChecked )).');';
A pergunta é antiga, mas gostaria de estender o tópico com outra resposta.
O que quero dizer é que a maneira mais fácil de conseguir isso é apenas agrupar várias consultas com uma transação. A resposta aceita
INSERT ... ON DUPLICATE KEY UPDATE
é um bom truque, mas é preciso estar ciente de suas desvantagens e limitações:"Field 'fieldname' doesn't have a default value"
aviso do MySQL, mesmo que não insira uma única linha. Isso causará problemas se você decidir ser rigoroso e transformar os avisos do mysql em exceções de tempo de execução no seu aplicativo.Fiz alguns testes de desempenho para três das variantes sugeridas, incluindo a
INSERT ... ON DUPLICATE KEY UPDATE
variante, uma variante com a cláusula "case / when / then" e uma abordagem ingênua com a transação. Você pode obter o código python e os resultados aqui . A conclusão geral é que a variante com declaração de caso é duas vezes mais rápida que duas outras variantes, mas é muito difícil escrever um código correto e seguro para injeção, portanto, eu pessoalmente adiro à abordagem mais simples: usar transações.Edit: As descobertas de Dakusan provam que minhas estimativas de desempenho não são muito válidas. Por favor, veja esta resposta para outra pesquisa mais elaborada.
fonte
Não sei por que outra opção útil ainda não foi mencionada:
fonte
Todos os itens a seguir se aplicam ao InnoDB.
Sinto que é importante conhecer a velocidade dos três métodos diferentes.
Existem 3 métodos:
Acabei de testar isso, e o método INSERT era 6,7x mais rápido do que o método TRANSACTION. Eu tentei em um conjunto de 3.000 e 30.000 linhas.
O método TRANSACTION ainda precisa executar cada consulta individualmente, o que leva tempo, apesar de agrupar os resultados na memória, ou algo assim, durante a execução. O método TRANSACTION também é bastante caro nos logs de replicação e consulta.
Pior ainda, o método CASE foi 41,1x mais lento que o INSERT com 30.000 registros (6,1x mais lento que TRANSACTION). E 75x mais lento no MyISAM. Os métodos INSERT e CASE chegaram a ~ 1.000 registros. Mesmo com 100 registros, o método CASE é MUITO MAIS rápido.
Portanto, em geral, acho que o método INSERT é melhor e mais fácil de usar. As consultas são menores e mais fáceis de ler e ocupam apenas 1 consulta de ação. Isso se aplica ao InnoDB e ao MyISAM.
Material bônus:
A solução para o problema da não-default-campo INSERT está para desligar temporariamente os modos SQL relevantes:
SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Salve osql_mode
primeiro se planeja revertê-lo.Como em outros comentários que eu vi, dizem que o auto_increment sobe usando o método INSERT, esse parece ser o caso no InnoDB, mas não no MyISAM.
O código para executar os testes é o seguinte. Também gera arquivos .SQL para remover a sobrecarga do interpretador php
fonte
Use uma tabela temporária
fonte
Isso deve funcionar para você.
Há uma referência no manual do MySQL para várias tabelas.
fonte
Por que ninguém menciona várias instruções em uma consulta ?
No php, você usa
multi_query
método da instância mysqli.Do manual php
Aqui está o resultado comparando com outros 3 métodos na atualização 30.000 bruta. O código pode ser encontrado aqui, com base na resposta de @Dakusan
Transação: 5.5194580554962
Inserção: 0.20669293403625
Caso: 16.474853992462
Multi: 0,0412278175354
Como você pode ver, a consulta de várias instruções é mais eficiente que a resposta mais alta.
Se você receber uma mensagem de erro como esta:
Você pode precisar aumentar o
max_allowed_packet
arquivo de configuração do mysql que está na minha máquina/etc/mysql/my.cnf
e depois reiniciar o mysqld.fonte
$mysqli->multi_query($sql)
levou "0" segundos. No entanto, consultas subsequentes falharam, fazendo com que eu fizesse um "programa" separado.Existe uma configuração que você pode alterar, chamada 'multi statement', que desativa o 'mecanismo de segurança' do MySQL implementado para evitar (mais de um) comando de injeção. Típico da implementação "brilhante" do MySQL, também impede que o usuário faça consultas eficientes.
Aqui ( http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html ) estão algumas informações sobre a implementação C da configuração.
Se você estiver usando PHP, poderá usar o mysqli para executar várias instruções (acho que o php já vem com o mysqli há algum tempo)
Espero que ajude.
fonte
mysqli::begin_transaction(..)
antes de enviar a consulta emysql::commit(..)
depois. Ou useSTART TRANSACTION
como primeira eCOMMIT
como última instrução na própria consulta.Você pode alternar a mesma tabela para fornecer os IDs pelos quais deseja inserir (se estiver fazendo uma atualização linha por linha:
Além disso, deve parecer óbvio que você também pode atualizar de outras tabelas. Nesse caso, a atualização funciona como uma instrução "SELECT", fornecendo os dados da tabela que você está especificando. Você está declarando explicitamente em sua consulta os valores de atualização para que a segunda tabela não seja afetada.
fonte
Você também pode estar interessado em usar junções nas atualizações, o que também é possível.
Editar: se os valores que você está atualizando não vierem de outro lugar no banco de dados, será necessário emitir várias consultas de atualização.
fonte
E agora o caminho mais fácil
fonte
usar
Observe:
fonte
O seguinte atualizará todas as linhas em uma tabela
O próximo atualizará todas as linhas em que o valor da Coluna2 é superior a 5
Há todo o exemplo da Unkwntech de atualizar mais de uma tabela
fonte
Sim .. é possível usando a instrução sql INSERT ON DUPLICATE KEY UPDATE .. sintaxe: INSERT INTO table_name (a, b, c) VALUES (1,2,3), (4,5,6) ON DUPLICATE KEY UPDATE a = VALORES (a), b = VALORES (b), c = VALORES (c)
fonte
Isso deve alcançar o que você está procurando. Basta adicionar mais IDs. Eu testei.
fonte
// Você apenas constrói em php como
Então você pode atualizar a tabela de furos com uma consulta
fonte
something
asomething
)