0

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

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 的功能,但使用更新语句代替。这是可行的,还是我需要一个单独的语句来首先删除任何现有条目?

4

1 回答 1

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而不是删除行。

于 2013-07-29T17:23:42.183 回答