Inserción condicional de MySQL


Estoy teniendo dificultades para formar un INSERTO condicional

Tengo x_table con columnas (instancia, usuario, elemento) donde el ID de instancia es único. Quiero insertar una nueva fila solo si el usuario ya no tiene un elemento dado.

Por ejemplo, tratando de insertar 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 

Cualquier ayuda u orientación en la dirección correcta sería muy apreciada.

Author: The Unknown, 2009-05-27

12 answers

Si su DBMS no impone limitaciones sobre la tabla de la que selecciona cuando ejecuta un insert, intente:

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)

En esto, dual es una tabla con una sola fila (que se encuentra originalmente en Oracle, ahora también en otros lugares). La lógica es que la instrucción SELECT genera una sola fila de datos con los valores requeridos, pero solo cuando los valores no se encuentran ya.

Alternativamente, mira la instrucción MERGE.

 98
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-27 04:31:08

También puede usar INSERT IGNORE que ignora silenciosamente la inserción en lugar de actualizar o insertar una fila cuando tiene un índice único en (usuario, elemento).

La consulta se verá así:

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

Puede agregar el índice único con CREATE UNIQUE INDEX user_item ON x_table (user, item).

 42
Author: MrD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-25 06:52:03

¿Alguna vez has probado algo así?

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;
 24
Author: temple,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-15 21:35:16

Con un UNIQUE(user, item), haga:

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

El bit user=123 es un "no-op" para coincidir con la sintaxis de la cláusula ON DUPLICATE sin hacer realmente nada cuando hay duplicados.

 10
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-27 04:37:40

En caso de que no desee establecer una restricción única, esto funciona como un encanto:

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

Espero que ayude !

 2
Author: Gew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-29 11:23:48

Si agrega una restricción que (x_table.usuario, x_table.item) es único, luego se producirá un error al insertar otra fila con el mismo usuario y el mismo item.

Eg:

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
 1
Author: NickZoic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-27 04:00:26

Aunque es bueno verificar la duplicación antes de insertar sus datos, le sugiero que ponga una restricción/índice único en sus columnas para que no se puedan insertar datos duplicados por error.

 1
Author: Beatles1692,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-27 04:03:02

Lo que quieres es INSERT INTO table (...) SELECT ... WHERE .... desde MySQL 5.6 manual .

En tu caso es:

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

O tal vez ya que no está utilizando ninguna lógica complicada para determinar si se debe ejecutar el INSERT o no, solo podría establecer una tecla UNIQUE en la combinación de estas dos columnas y luego usar INSERT IGNORE.

 1
Author: martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-27 18:49:13
Insert into x_table (instance, user, item) values (919191, 123, 456) 
    where ((select count(*) from x_table where user=123 and item=456) = 0);

La sintaxis puede variar dependiendo de su BD...

 0
Author: Rick J,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-27 03:56:41

Una ligera modificación en la respuesta de Alex, también puede hacer referencia al valor de la columna existente:

Insert into x_table (instance, user, item) values (919191, 123, 456) 
  ON DUPLICATE KEY UPDATE user=user
 0
Author: Danny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-25 05:50:04

Así que este es 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
 0
Author: xsubira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-13 13:01:09

Puede utilizar la siguiente solución para resolver su problema:

INSERT INTO x_table(instance, user, item) 
    SELECT 919191, 123, 456
        FROM dual
        WHERE 123 NOT IN (SELECT user FROM x_table)
 0
Author: Keith Becker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-16 00:28:31