如何执行UPSERT以便我可以在更新部分中使用新旧值

WPF*_*Bie 64 mysql performance upsert

愚蠢而简单的例子:假设我有一个表'Item',其中我保存了收到的项目的总数.

Item_Name              Items_In_Stock
Run Code Online (Sandbox Code Playgroud)

项目名称是主键.当我收到数量为X的项目A时,如何实现以下目标.

如果该项目不存在,我为项目A插入一个新的,并将库存中的项目设置为X,如果存在库存中的项目为Y的记录,则库存中的项目中的新值为(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' )
Run Code Online (Sandbox Code Playgroud)

我的问题是我的实际表中有多列.在更新部分中编写多个select语句是个好主意吗?

当然我可以在代码中完成它,但有更好的方法吗?

Mic*_*.V. 134

正如我的评论中所提到的,您不必执行子选择来引用导致ON DUPLICATE KEY触发的行.因此,在您的示例中,您可以使用以下内容:

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

请记住,大多数事情都非常简单,如果你发现自己过于复杂的事情应该很简单,那么你最有可能做错了:)

  • **注意:** 看起来如果 PK 字段是自动增量,则 ON DUPLICATE KEY UPDATE 子句会增加自动增量值,无论触发了哪种效果(INSERT 或 UPDATE)(使用 InnoDB 引擎时)。参见:[MySQL 参考手册](https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html) (2认同)
  • 为了防止代码重复,您应该使用“new_items_count = new_items_count + VALUES(items_in_stock)” (2认同)
  • 可以使用“REPLACE”查询来完成此操作吗?这样就简单多了 (2认同)

Sal*_*lim 11

你可以从这个例子中得到一个想法:

假设您要添加用户明智的七天数据

它应该具有userid和day的唯一值

UNIQUE KEY `seven_day` (`userid`,`day`)
Run Code Online (Sandbox Code Playgroud)

这是表格

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`)
);
Run Code Online (Sandbox Code Playgroud)

你的查询将是

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

例:

<?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);
}
?>
Run Code Online (Sandbox Code Playgroud)

您的数据将在表格中:

+--------+-----+-------+-------+
| userid | day | open  | close |
+--------+-----+-------+-------+
| 1001   | sat | 03.01 | 33.01 |
| 1001   | sun | 02.01 | 22.01 |
| 1002   | mon | 07.01 | 07.01 |
+--------+-----+-------+-------+
Run Code Online (Sandbox Code Playgroud)

  • 切勿将数据直接连接到查询中.使用PDO或类似的准备/参数化查询.在这个例子的情况下,至少转义数据是合适的. (6认同)

Nav*_*Nav 7

虽然Michael的答案是正确的,但您需要了解更多以编程方式执行upsert:

首先,创建表并指定您想要唯一索引的列:

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`)
)
Run Code Online (Sandbox Code Playgroud)

然后在其中插入一些值:

INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );
Run Code Online (Sandbox Code Playgroud)

尝试再做同样的事情,你会得到一个重复的键错误,因为cellId并且entityRowId是相同的:

INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );
Run Code Online (Sandbox Code Playgroud)

键'id_ce'重复输入'1-199'

这就是我们使用upsert命令的原因:

INSERT INTO Cell ( cellId, attributeId, entityRowId, value)
VALUES( 1, 6, 199, 300.0 )
ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`)
Run Code Online (Sandbox Code Playgroud)

此命令将1.0已存在的值作为值并执行a value = value + 300.0.

因此,即使执行上述命令后,表中只有一行,值也是如此301.0.

  • 这可能不是公认的答案,但额外的细节对我来说很长,并给了它一个upvote. (2认同)