Inserção Condicional do MySQL

Estou com dificuldades para formar um INSERT condicional

Eu tenho x_table com colunas (instância, usuário, item) onde o ID da instância é único. Eu quero inserir uma nova linha somente se o usuário já não tiver um determinado item.

Por exemplo, tentando inserir instance = 919191 user = 123 item = 456

Insert into x_table (instance, user, item) values (919191, 123, 456) ONLY IF there are no rows where user=123 and item=456 

Qualquer ajuda ou orientação na direção correta seria muito apreciada.

Se o seu SGBD não impuser limitações em qual tabela você selecionou ao executar uma inserção, tente:

 INSERT INTO x_table(instance, user, item) SELECT 919191, 123, 456 FROM dual WHERE NOT EXISTS (SELECT * FROM x_table WHERE user = 123 AND item = 456) 

Neste, dual é uma tabela com apenas uma linha (encontrada originalmente no Oracle, agora também em outro lugar). A lógica é que a instrução SELECT gera uma única linha de dados com os valores requeridos, mas somente quando os valores não são encontrados.

Alternativamente, olhe para a instrução MERGE.

Você também pode usar INSERT IGNORE que silenciosamente ignora a inserção em vez de atualizar ou inserir uma linha quando você tem um índice exclusivo em (usuário, item).

A consulta ficará assim:

 INSERT IGNORE INTO x_table(instance, user, item) VALUES (919191, 123, 456) 

Você pode adicionar o índice exclusivo com CREATE UNIQUE INDEX user_item ON x_table (user, item) .

Você já tentou algo assim?

 INSERT INTO x_table SELECT 919191 as instance, 123 as user, 456 as item FROM x_table WHERE (user=123 and item=456) HAVING COUNT(*) = 0; 

Com um UNIQUE(user, item) , faça:

 Insert into x_table (instance, user, item) values (919191, 123, 456) ON DUPLICATE KEY UPDATE user=123 

o user=123 bits é um “no-op” para coincidir com a syntax da cláusula ON DUPLICATE sem realmente fazer nada quando houver duplicatas.

Caso você não queira definir uma restrição exclusiva, isso funciona como um encanto:

 INSERT INTO `table` (`column1`, `column2`) SELECT 'value1', 'value2' FROM `table` WHERE `column1` = 'value1' AND `column2` = 'value2' HAVING COUNT(`column1`) = 0 

Espero que ajude !

Se você adicionar uma restrição que (x_table.user, x_table.item) seja exclusiva, inserir outra linha com o mesmo usuário e item falhará.

por exemplo:

 mysql> create table x_table ( instance integer primary key auto_increment, user integer, item integer, unique (user, item)); Query OK, 0 rows affected (0.00 sec) mysql> insert into x_table (user, item) values (1,2),(3,4); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> insert into x_table (user, item) values (1,6); Query OK, 1 row affected (0.00 sec) mysql> insert into x_table (user, item) values (1,2); ERROR 1062 (23000): Duplicate entry '1-2' for key 2 

Embora seja bom verificar se há duplicação antes de inserir seus dados, sugiro que você coloque uma restrição / índice exclusivo em suas colunas para que nenhum dado duplicado possa ser inserido por engano.

O que você quer é INSERT INTO table (...) SELECT ... WHERE ... do manual do MySQL 5.6 .

No seu caso é:

 INSERT INTO x_table (instance, user, item) SELECT 919191, 123, 456 WHERE (SELECT COUNT(*) FROM x_table WHERE user=123 AND item=456) = 0 

Ou talvez, como você não está usando nenhuma lógica complicada para determinar se deve executar o INSERT ou não, basta definir uma chave UNIQUE na combinação dessas duas colunas e, em seguida, usar INSERT IGNORE .

 Insert into x_table (instance, user, item) values (919191, 123, 456) where ((select count(*) from x_table where user=123 and item=456) = 0); 

A syntax pode variar dependendo do seu DB …

Ligeira modificação na resposta de Alex, você também poderia apenas referenciar o valor da coluna existente:

 Insert into x_table (instance, user, item) values (919191, 123, 456) ON DUPLICATE KEY UPDATE user=user 

Então este aqui significa PostgreSQL

 INSERT INTO x_table SELECT NewRow.* FROM (SELECT 919191 as instance, 123 as user, 456 as item) AS NewRow LEFT JOIN x_table ON x_table.user = NewRow.user AND x_table.item = NewRow.item WHERE x_table.instance IS NULL 

Você pode usar a seguinte solução para resolver seu problema:

 INSERT INTO x_table(instance, user, item) SELECT 919191, 123, 456 FROM dual WHERE 123 NOT IN (SELECT user FROM x_table)