Eu recomendaria usar INSERT...ON DUPLICATE KEY UPDATE
.
Se você usar INSERT IGNORE
, a linha não será realmente inserida se resultar em uma chave duplicada. Mas a instrução não irá gerar um erro. Em vez disso, gera um aviso. Esses casos incluem:
- Inserir uma chave duplicada em colunas com
PRIMARY KEY
ou UNIQUE
restrições.
- Inserir um NULL em uma coluna com uma
NOT NULL
restrição.
- Inserir uma linha em uma tabela particionada, mas os valores inseridos não são mapeados para uma partição.
Se você usa REPLACE
, o MySQL realmente faz um DELETE
seguido por um INSERT
internamente, o que tem alguns efeitos colaterais inesperados:
- Um novo ID de incremento automático é alocado.
- Linhas dependentes com chaves estrangeiras podem ser excluídas (se você usar chaves estrangeiras em cascata) ou impedir a
REPLACE
.
- Os gatilhos que disparam
DELETE
são executados desnecessariamente.
- Os efeitos colaterais também são propagados para réplicas.
correção: tanto REPLACE
e INSERT...ON DUPLICATE KEY UPDATE
estão fora do padrão, proprietária invenções específico para MySQL. ANSI SQL 2003 define uma MERGE
declaração que pode resolver a mesma necessidade (e mais), mas o MySQL não suporta a MERGE
declaração.
Um usuário tentou editar esta postagem (a edição foi rejeitada pelos moderadores). A edição tentou adicionar uma reivindicação que INSERT...ON DUPLICATE KEY UPDATE
faz com que um novo ID de incremento automático seja alocado. É verdade que o novo ID é gerado , mas não é usado na linha alterada.
Veja a demonstração abaixo, testada com o Percona Server 5.5.28. A variável de configuração innodb_autoinc_lock_mode=1
(o padrão):
mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 10 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
O exemplo acima demonstra que a instrução IODKU detecta a duplicata e chama a atualização para alterar o valor de u
. Observe que AUTO_INCREMENT=3
indica que um ID foi gerado, mas não usado na linha.
Considerando REPLACE
que exclui a linha original e insere uma nova linha, gerando e armazenando um novo ID de incremento automático:
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+
INSERT ... ON DUPLICATE KEY UPDATE ...
declarações. Muitos dados são duplicados e resultaram em uma instância do AI PK aumentando de 17.029.941 para 46.271.740 entre duas linhas. Essa geração de uma nova IA sempre significa que seu alcance pode ser rapidamente preenchido e você precisa fazer a limpeza. Esta tabela tem apenas duas semanas!Caso você queira ver o que tudo isso significa, aqui está um golpe por golpe:
A chave primária é baseada nas duas colunas desta tabela de referência rápida. Uma chave primária requer valores exclusivos.
Vamos começar:
observe que o acima economizou muito trabalho extra ao definir a coluna igual a si mesma, nenhuma atualização realmente necessária
e agora alguns testes de várias linhas:
nenhuma outra mensagem foi gerada no console e agora possui esses 4 valores nos dados da tabela. Eu apaguei tudo, exceto (1,1), para poder testar no mesmo campo de jogo
Então aí está. Como tudo foi realizado em uma tabela nova, quase sem dados e sem produção, os tempos de execução foram microscópicos e irrelevantes. Qualquer pessoa com dados do mundo real seria mais que bem-vinda para contribuir com eles.
fonte
INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
.Algo importante a acrescentar: Ao usar o INSERT IGNORE e você tem violações de chave, o MySQL NÃO gera um aviso!
Se você tentar, por exemplo, inserir 100 registros por vez, com um defeituoso, entrará no modo interativo:
Como você vê: sem avisos! Esse comportamento é mesmo descrito incorretamente na documentação oficial do Mysql.
Se seu script precisar ser informado, se alguns registros não foram adicionados (devido a violações de teclas), você deve chamar mysql_info () e analisá-lo para o valor "Duplicados".
fonte
mysqli_affected_rows()
saber se o queINSERT
realmente aconteceu.Cannot add or update a child row: a foreign key constraint fails
e nenhuma linha (mesmo as válidas) são adicionadas.INSERT IGNORE
, chaves duplicadas são ignoradas sem erro ou aviso.Eu uso rotineiramente
INSERT IGNORE
e parece exatamente o tipo de comportamento que você também está procurando. Desde que você saiba que as linhas que causariam conflitos de índice não serão inseridas e você planeje seu programa adequadamente, isso não deverá causar problemas.fonte
Sei que isso é antigo, mas adicionarei esta observação caso alguém (como eu) chegue a esta página enquanto tenta encontrar informações sobre INSERT..IGNORE.
Como mencionado acima, se você usar INSERT..IGNORE, os erros que ocorrem durante a execução da instrução INSERT serão tratados como avisos.
Uma coisa que não é mencionada explicitamente é que INSERT..IGNORE fará com que valores inválidos sejam ajustados aos valores mais próximos quando inseridos (enquanto valores inválidos causariam a interrupção da consulta se a palavra-chave IGNORE não fosse usada).
fonte
ON DUPLICATE KEY UPDATE não está realmente no padrão. É tão padrão quanto REPLACE. Consulte SQL MERGE .
Essencialmente, ambos os comandos são versões de sintaxe alternativa dos comandos padrão.
fonte
Replace
Into parece ser uma opção. Ou você pode verificar comIsto irá inserir ou excluir e depois inserir. Costumo fazer um
IF NOT EXISTS
cheque primeiro.fonte
REPLACE
exclui todas as linhas na tabela combinando com qualquerPRIMARY
ouUNIQUE
chave, entãoINSERTs
. Isso é potencialmente muito mais trabalho que o IODKU.Perigo potencial de INSERIR IGNORAR. Se você estiver tentando inserir um valor VARCHAR por mais tempo, a coluna foi definida com - o valor será truncado e inserido, mesmo que o modo estrito esteja ativado.
fonte
Se usar
insert ignore
umaSHOW WARNINGS;
declaração no final do seu conjunto de consultas, será exibida uma tabela com todos os avisos, incluindo quais IDs foram as duplicatas.fonte
SHOW WARNINGS;
apenas parece afetar a consulta mais recente. Quaisquer declarações anteriores não são acumuladas, se você tiver mais de uma única declaração.Se você deseja inserir na tabela e no conflito da chave primária ou do índice exclusivo, ele atualizará a linha conflitante em vez de inseri-la.
Sintaxe:
Agora aqui, essa instrução de inserção pode parecer diferente do que você viu anteriormente. Esta instrução de inserção tentando inserir uma linha na tabela1 com o valor de aeb na coluna column1 e column2 respectivamente.
Vamos entender essa afirmação em profundidade:
Por exemplo: aqui coluna1 é definida como a chave primária na tabela1.
Agora, se na tabela1 não houver linha com o valor "a" na coluna1. Portanto, esta instrução irá inserir uma linha na tabela1.
Agora, se na tabela1 houver uma linha com o valor "a" na coluna2. Portanto, essa instrução atualizará o valor da coluna2 da linha com "c", onde o valor da coluna1 é "a".
Portanto, se você deseja inserir uma nova linha, atualize essa linha no conflito da chave primária ou do índice exclusivo.
Leia mais neste link
fonte
INSERT...ON DUPLICATE KEY UPDATE
é preferido para impedir o gerenciamento inesperado de exceções.Esta solução funciona quando você possui ** 1 restrição exclusiva **
No meu caso, eu sei disso
col1
ecol2
faço um índice composto exclusivo.Ele controla o erro, mas não lança uma exceção em duplicado. Em relação ao desempenho, a atualização com o mesmo valor é eficiente, pois o MySQL percebe isso e não o atualiza
A idéia de usar essa abordagem veio dos comentários em phpdelusions.net/pdo .
fonte