主键重复的更新语句

时间:2013-07-29 15:03:26

标签: mysql

我有三个表的数据。我正在尝试执行将数据从一个用户移动到另一个用户的操作 - 某些数据可能不存在,并且目标可能已经存在并且需要被覆盖。这就是我所拥有的:

UPDATE Table1 t1
LEFT JOIN Table2 t2 USING (UserName)
LEFT JOIN Table3 t3 USING (UserName)
SET t1.UserName = @newUser, t2.UserName = @newUser, t3.UserName = @newUser
WHERE t1.UserName = @oldUser

这样可以正常工作,除非表中已经有新用户名的数据。我得到(正如您所期望的)重复键错误。是否有任何解决方案将它保存在单个SQL语句中?我本质上想模仿INSERT ... ON DUPLICATE UPDATE的功能,但改为使用更新语句。这是可行的,还是我需要一个单独的语句来首先删除任何现有的条目?

1 个答案:

答案 0 :(得分:1)

如果您的应用程序有多个客户端可能同时命中它,您将希望在事务中执行此操作。事实上,您尝试在单个语句中尝试在事务中执行此操作。但似乎您的业务规则比单个语句可以实现的要复杂一些。

首先,执行此操作以开始您的交易。 (许多与MySQL的语言绑定提供了您可以使用的特定函数来代替发出此语句。)

START TRANSACTION;

然后,发出此查询。 (它适用于InnoDB,但不适用于MyISAM。)如果@newUser名称已经存在,它会为用户锁定行。

  SELECT Username
    FROM Table1
   WHER Username = @newUser
     FOR UPDATE;

然后,从您的应用程序语言中,检索此处的行数。它应该是零(意味着这个@newUser尚不存在)或一个(意思是它)。如果用户确实存在,请删除。

  DELETE FROM Table3 WHERE Username = @newUser;
  DELETE FROM Table2 WHERE Username = @newUser;
  DELETE FROM Table3 WHERE Username = @newUser;

我首先尝试删除fk表,然后删除主表。因此顺序相反。如果您关心这些表中是否已存在行,则可以检查每个查询所影响的数字或行。

接下来,发出您的update声明,即您提问的声明。

最后,做一个提交。

COMMIT;

还有一个想法:如果@newUser已经存在,您可以考虑将该用户名更改为某些虚构字符串,例如former_user_12345,而不是删除行。