【问题标题】:MySQL update a record on duplicate key update (merge)MySQL更新重复键更新(合并)的记录
【发布时间】:2021-06-22 01:34:41
【问题描述】:

我有一个表products,其架构如下:

CREATE TABLE `products` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `user_id` bigint unsigned NOT NULL,
  `article_id` bigint unsigned NOT NULL,
  `price_cents` int unsigned NOT NULL,
  `quantity` smallint NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_products_unique` (`user_id`,`article_id`,`price_cents`),
  KEY `fk_products_article` (`article_id`),
  CONSTRAINT `fk_products_article` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_products_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB

现在我可以用这个查询做 INSERT:

INSERT INTO `products` (`user_id`,`article_id`,`price_cents`,`quantity`) 
VALUES (1,1,200,1) 
ON DUPLICATE KEY UPDATE `price_cents`=VALUES(`price_cents`),`quantity`=quantity+VALUES(`quantity`)

所以现在我有 1 个产品 (ID 1),数量为 1,价格为 200。 现在我插入另外 2 个产品:

INSERT INTO `products` (`user_id`,`article_id`,`price_cents`,`quantity`) 
VALUES (1,1,200,1),(1,1,199,1) 
ON DUPLICATE KEY UPDATE `price_cents`=VALUES(`price_cents`),`quantity`=quantity+VALUES(`quantity`)

现在我有 2 件产品,一件 (ID 1) 的数量为 2,价格为 200,另一件 (ID 2) 的数量为 1,价格为 199。

很好。

现在问题来了:我想更新价格为 199 的产品并将新价格设置为 200。我要做的是:

INSERT INTO `products` (`id`,`user_id`,`article_id`,`price_cents`,`quantity`) 
VALUES (2,1,1,200,1) 
ON DUPLICATE KEY UPDATE `price_cents`=VALUES(`price_cents`),`quantity`=quantity+VALUES(`quantity`)

而我想要的是ID为1、价格为200、数量为3的单一产品,但我得到Number:0x426, Message: "Duplicate entry '1-1-200' for key 'products.idx_products_unique',因为MySQL不会删除ID为2的产品。

有没有办法在 MySQL 中实现这一点(请记住,我想批量执行这些操作)?

【问题讨论】:

  • 问题是重复键在另一条记录中,所以你不能用一条sql语句来做到这一点。检测到dupkucate key错误后,需要删除价格为199的记录,更新价格为200行的数量。
  • 您有 2 个唯一约束 - 主键和 idx_products_unique。如果由于一个约束违反而触发更新,并且更新的值导致另一个约束违反(您的选择),则查询失败。
  • 将价格作为唯一键的一部分似乎不正常。这意味着您持有 相同 价格不同的产品??
  • @RickJames 准确
  • 您提到“批量”做事。请详细说明和/或举例。另外,批次中可能有多少个项目?我认为可能有一种方法可以在 2 个 SQL 语句中批处理任意数量的项目(一个用于更新,一个用于“合并”),但我没有仔细考虑细节。 (没有自动方法可以在单个语句中完成。)

标签: mysql updates upsert


【解决方案1】:

不要在语句中使用id。一个 IODKU 完成整个任务:

INSERT INTO t  (`user_id`,`article_id`,`price_cents`,`quantity`)
    ...
    ON DUPLICATE KEY UPDATE
        quantity = quantity + VALUES(quantity)

其中... 是一个批次:VALUES (11,22,33), ...SELECT (uid,aid,cents) FROM temp

(可选地,去掉 id 并将 3 列唯一索引升级为主索引。)

【讨论】:

  • 我试过没有ID,但我得到了同样的错误。
  • 告诉我你的 IODKU 和 CREATE TABLE 没有 id
【解决方案2】:

您应该使用合并语句,例如: 您有两张桌子,ProductsProducts info 您想合并两者但不想包含重复项。 使用以下

MERGE Products P
USING Products_Info PI
ON (PI.ProductID = P.ProductID)
WHEN MATCHED
THEN UPDATE SET
P.Product_Name = PI.Product_Name,
P.Cost = PI.Cost
WHEN NOT MATCHED BY TARGET
THEN INSERT (Product_ID, Product_Name, Cost/quantity)
VALUES(PI.ProductID,PI.Product_Name,PI.Cost)
WHEN NOT MATCHED BY SOURCE
THEN DELETE;

【讨论】:

  • 该问题被标记为与 MySQL 相关。 MySQL 中没有 MERGE。
【解决方案3】:

我认为你的设计不符合你的意图。

摆脱

唯一键idx_products_unique (user_id,article_id,price_cents),

如果您打算通过它进行查询,您可以将其设为非唯一索引。

另外 - 我认为您没有正确使用数据库...

您应该只拥有记录 - 带有值的原始数据。

您应该将尝试聚合为视图或查询的值(使用分组依据)。

【讨论】:

    猜你喜欢
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 2013-12-05
    • 2015-01-24
    • 2018-10-11
    • 2012-04-27
    相关资源
    最近更新 更多