Comment effectuer un UPSERT afin que je puisse utiliser les anciennes et les nouvelles valeurs dans la partie mise à jour

Exemple stupide mais simple: Supposons que j’ai un tableau ‘Item’ où je garde les totaux des articles reçus.

Item_Name Items_In_Stock 

Le nom de l’article est la clé primaire ici. Comment est-ce que j’obtiens le suivant quand je reçois l’article A en quantité X.

Si l’élément n’existe pas, j’insère un nouvel enregistrement pour l’élément A et place les articles en stock à X et s’il existe un enregistrement où les articles en stock étaient Y, la nouvelle valeur des articles en stock est (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' ) 

Mon problème est que j’ai plusieurs colonnes dans ma table réelle. Est-ce une bonne idée d’écrire plusieurs instructions select dans la partie mise à jour?

Bien sûr, je peux le faire en code, mais y a-t-il un meilleur moyen?

    Comme mentionné dans mon commentaire, vous n’avez pas besoin de faire la sous-sélection pour faire référence à la ligne à l’origine de ON DUPLICATE KEY. Ainsi, dans votre exemple, vous pouvez utiliser les éléments suivants:

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

    Rappelez-vous que la plupart des choses sont très simples, si vous vous surprenez à compliquer quelque chose qui devrait être simple, alors vous le faites probablement de la mauvaise façon 🙂

    Vous pouvez avoir une idée de cet exemple:

    Supposons que vous souhaitiez append des données sept jours par utilisateur

    Il devrait avoir une valeur unique pour userid et day like

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

    Voici la table

     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`) ); 

    Et votre requête sera

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

    Exemple:

     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); } ?> 

    Vos données seront dans la table:

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

    Bien que la réponse de Michael soit la bonne, vous devez en savoir un peu plus pour faire le programme par programme:

    Tout d’abord, créez votre table et spécifiez les colonnes sur lesquelles vous voulez un index unique:

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

    Puis insérez des valeurs dans celui-ci:

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

    Essayez de refaire la même chose et vous obtiendrez une erreur de clé en double, car cellId et entityRowId sont identiques:

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

    Entrée en double ‘1-199’ pour la clé ‘id_ce’

    C’est pourquoi nous utilisons la commande upsert:

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

    Cette commande prend la valeur 1.0 qui existe déjà comme valeur et fait une value = value + 300.0 .

    Donc, même après l’exécution de la commande ci-dessus, il n’y aura qu’une seule ligne dans la table et la valeur sera 302.0 .

    C’est la syntaxe pour un upert

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