【问题标题】:update on duplicate key update更新重复密钥更新
【发布时间】:2012-11-20 04:34:50
【问题描述】:

我有一个表playerspoints,其中包含一个商店 ID 和一个玩家的 ID,以及一个玩家的积分。

  SHOP_ID   |     PLAYER_ID     |  POINTS
  ----------------------------------------
      1     |        7          |     66
      2     |        4          |     33

我想做的是将积分从一家商店转移到另一家。

  • 问题:商店 id 和玩家 id 形成一个唯一索引。
  • 我想要做的是重复密钥更新,而不是让它失败,将一个条目的点添加到另一个条目并删除“来自”条目。

类似:

UPDATE `playerspoints`
SET `boardId`=$to
WHERE `boardId`=$from
ON DUPLICATE KEY UPDATE `points`=.... 

你明白了吗?

【问题讨论】:

  • 我的猜测是,使用 2(ish) 查询和 if/else 块会更简单。你想这样做有什么特别的原因吗?
  • 充分利用语言的优势是一种很好的做法。更重要的是发现事物,并以更快的方式使事情成为可能。
  • 我真的希望这有proper SQL escaping 如果它被部署到生产环境中。看到这样的裸变量令人担忧。
  • @DeusDeceit:啊,我完全明白了。我认为您对此不走运,但您可以尝试使用存储过程;)
  • 所有变量都被 tadman 先生转义并正确使用。如果您有更多建议,请执行。

标签: mysql sql-update on-duplicate-key


【解决方案1】:

您只能在ON DUPLICATE KEY 区域中的一个冲突行的上下文中进行更改。此外,据我所知,这是INSERT 语句的一个属性。

您需要的是一个简单的分类帐,您可以在其中记录余额中的加减,然后手动或使用触发器将它们制成表格。

例如,最简单的方法是:

INSERT INTO points_adjustments (boardId_from, boardId_to, points)
  VALUES (?, ?, ?)

这可能更容易表示为一对条目:

INSERT INTO points_adjustments (boardId, points)
  VALUES (?, ?)

您将为 +n 点添加一个条目,为 -n 添加一个匹配的条目。您可以随时使用SUM(points) 获得余额。您可以将其包含在 VIEW 中以使检索更容易,或者如果您愿意,可以使用触发器将总和非规范化到另一个表的列中。

一个简单的触发器将为每个受影响的boardId 发出以下语句:

INSERT INTO balances (boardId, points) VALUES (?, ?)
  ON DUPLICATE KEY SET points=points+VALUES(points)

这首先避免了密钥冲突,并提供了已发生交易的可审计记录。

无论如何,要自动执行所有这些操作,您可能必须使用触发器。

第三方编辑

来自文档INSERT ... ON DUPLICATE KEY UPDATE Statement

一般来说,您应该尽量避免使用 ON DUPLICATE KEY UPDATE 具有多个唯一索引的表上的子句。

【讨论】:

  • 我喜欢这个解决方案,但在我认为是时候使用触发器之前,我从未使用过触发器。至于转义... $from = (int)mysql_real_escape_string($_REQUEST['from']); $to = (int)mysql_real_escape_string($_REQUEST['to']); $delete = $condition[mysql_real_escape_string($_REQUEST['delete'])]; $contest = $condition[mysql_real_escape_string($_REQUEST['contest'])];还有什么我可以做的吗?
  • 是的。触发器将是合乎逻辑的下一步。违反约束的自动删除是一个雄心勃勃的想法:)
  • 是的...使用 PDO(或其他 DB 抽象库)。
  • 在 2012 年任何使用 mysql_real_escape_string 都是可怕的。请,为了您自己的理智,请使用 PDO 之类的明智之举。使用 SQL 占位符,这将 字面上 折叠成两个简单易读的行。如果你使用? 或者更好的命名参数,那么你只是一个bindParam 调用或两个远离安全的地方。学习如何有效地使用 PDO 需要所有 thirty minutes。
  • 这也是“帮助,我的石箭遇到问题,如何用矛乳齿象”类型的答案。有许多好的ORM database layer PHP 包可以使这种数据库的工作变得相当容易。进行低级 SQL 调用和手写查询并不有趣,而且效率也不高。
【解决方案2】:

没有。在 MySQL 中,您不能在违反约束时删除记录。您可能会执行更新前触发器来检查即将发生的约束违规,但即便如此(从 5.1 开始)您也无法修改同一个表的数据(在这种情况下这可能会导致无限循环)。

Tadman 的回答只完成了一半。我个人喜欢他的想法。

【讨论】:

    猜你喜欢
    • 2014-10-31
    • 2018-06-24
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 2011-09-30
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多