Cómo realizar un UPSERT para poder usar valores nuevos y antiguos en la parte de actualización

Ejemplo estúpido pero simple: Supongamos que tengo una tabla ‘Artículo’ donde guardo los totales de los artículos que reciben.

Item_Name Items_In_Stock 

El nombre del elemento es la clave principal aquí. Cómo logro lo siguiente cuando recibo el artículo A en cantidad X.

Si el artículo no existe, inserto un nuevo recodificado para el artículo A y coloco los artículos en stock en X y si existe un registro donde los artículos en stock eran Y, entonces el nuevo valor en los artículos en stock es (X + Y)

 INSERT INTO `item` (`item_name`, items_in_stock) VALUES( 'A', 27) ON DUPLICATE KEY UPDATE `new_items_count` = 27 + (SELECT items_in_stock where item_name = 'A' ) 

Mi problema es que tengo varias columnas en mi mesa real. ¿Es una buena idea escribir múltiples declaraciones de selección en la parte de actualización?

Por supuesto que puedo hacerlo en código pero ¿hay una mejor manera?

Como mencioné en mi comentario, no es necesario hacer la subselección para hacer referencia a la fila que está haciendo que ON DUPLICATE KEY se active. Entonces, en tu ejemplo puedes usar lo siguiente:

 INSERT INTO `item` (`item_name`, items_in_stock) VALUES( 'A', 27) ON DUPLICATE KEY UPDATE `new_items_count` = `new_items_count` + 27 

Recuerda que la mayoría de las cosas son realmente simples, si te das cuenta de algo complicado que debería ser simple, entonces lo más probable es que lo estés haciendo de la manera incorrecta 🙂

Puede obtener una idea de este ejemplo:

Supongamos que desea agregar datos de siete días para el usuario

Debe tener un valor único para userid y día como

 UNIQUE KEY `seven_day` (`userid`,`day`) 

Aquí está la mesa

 CREATE TABLE `table_name` ( `userid` char(4) NOT NULL, `day` char(3) NOT NULL, `open` char(5) NOT NULL, `close` char(5) NOT NULL, UNIQUE KEY `seven_day` (`userid`,`day`) ); 

Y su consulta será

 INSERT INTO table_name (userid,day,open,close) VALUES ('val1', 'val2','val3','val4') ON DUPLICATE KEY UPDATE open='val3', close='val4'; 

Ejemplo:

 < ?php //If your data is $data= array( 'sat'=>array("userid"=>"1001", "open"=>"01.01", "close"=>"11.01"), 'sun'=>array("userid"=>"1001", "open"=>"02.01", "close"=>"22.01"), 'sat'=>array("userid"=>"1001", "open"=>"03.01", "close"=>"33.01"), 'mon'=>array("userid"=>"1002", "open"=>"08.01", "close"=>"08.01"), 'mon'=>array("userid"=>"1002", "open"=>"07.01", "close"=>"07.01") ); //If you query this in a loop //$conn = mysql_connect("localhost","root",""); //mysql_select_db("test", $conn); foreach($data as $day=>$info) { $sql = "INSERT INTO table_name (userid,day,open,close) VALUES ('$info[userid]', '$day','$info[open]','$info[close]') ON DUPLICATE KEY UPDATE open='$info[open]', close='$info[close]'"; mysql_query($sql); } ?> 

Sus datos estarán en la tabla:

 +--------+-----+-------+-------+ | userid | day | open | close | +--------+-----+-------+-------+ | 1001 | sat | 03.01 | 33.01 | | 1001 | sun | 02.01 | 22.01 | | 1002 | mon | 07.01 | 07.01 | +--------+-----+-------+-------+ 

Aunque la respuesta de Michael es la correcta, necesita saber un poco más para hacer el uploaded programmatically:

Primero, cree su tabla y especifique en qué columnas desea que aparezca un índice único:

 CREATE TABLE IF NOT EXISTS Cell ( cellId BIGINT UNSIGNED, attributeId BIGINT UNSIGNED, entityRowId BIGINT UNSIGNED, value DECIMAL(25,5), UNIQUE KEY `id_ce` (`cellId`,`entityRowId`) ) 

Luego inserte algunos valores en él:

 INSERT INTO Cell VALUES( 1, 6, 199, 1.0 ); 

Intente hacer lo mismo otra vez, y obtendrá un error de clave duplicada, porque cellId y entityRowId son los mismos:

 INSERT INTO Cell VALUES( 1, 6, 199, 1.0 ); 

Entrada duplicada ‘1-199’ para la clave ‘id_ce’

Es por eso que usamos el comando upsert:

 INSERT INTO Cell ( cellId, attributeId, entityRowId, value, s, l, p, t ) VALUES( 1, 6, 199, 300.0 ) ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`) 

Este comando toma el valor 1.0 que ya está allí como valor y tiene un value = value + 300.0 .

Entonces, incluso después de ejecutar el comando anterior, solo habrá una fila en la tabla, y el valor será 302.0 .

Esta es la syntax para un postre

 INSERT INTO `{TABLE}` (`{PKCOLUMN}`, `{COLUMN}`) VALUES (:value) ON DUPLICATE KEY UPDATE `{COLUMN}` = :value_dup';