Mysql:为不同的行交换数据

Mysql:为不同的行交换数据,mysql,sql,Mysql,Sql,假设一张桌子是这样的: ------------------------------------------ | id | name | color | calories | ------------------------------------------ | 1 | apple | red | 20 | | 2 | orange | orange | 10 | | 3 | grapes | gre

假设一张桌子是这样的:

------------------------------------------
| id |    name    |   color   | calories |
------------------------------------------
| 1  | apple      | red       | 20       |
| 2  | orange     | orange    | 10       |
| 3  | grapes     | green     | 5        |
| 4  | bananas    | yellow    | 15       |
| 5  | plum       | purple    | 25       |
------------------------------------------
如何将一行的值与另一行的值交换,使id号保持不变

例如:

SWAP ROW WITH ID "5" WITH ROW WITH ID "2"
结果:

------------------------------------------
| id |    name    |   color   | calories |
------------------------------------------
| 1  | apple      | red       | 20       |
| 2  | plum       | purple    | 25       |
| 3  | grapes     | green     | 5        |
| 4  | bananas    | yellow    | 15       |
| 5  | orange     | orange    | 10       |
------------------------------------------
请注意,除了id之外,所有值都是完整的。 我需要一个非常大的值列表来完成这项工作,所以我需要一个单行程序,或者最多,不需要创建临时表之类的东西

注意:id是唯一的


谢谢

因为ID是唯一的,所以很难只交换ID,交换列内容更容易。您可能需要这样的查询:

UPDATE
  yourtable t1 INNER JOIN yourtable t2
  ON (t1.id, t2.id) IN ((1,5),(5,1))
SET
  t1.color = t2.color,
  t1.name = t2.name,
  t1.calories = t2.calories

请参阅fiddle。

这里有一种临时存储值的方法,无需使用临时表或水果表中的虚拟行:

SELECT name, color, calories FROM fruit WHERE id = 2 INTO @name, @color, @calories;

UPDATE fruit AS f1, fruit AS f2
SET
 f1.name = f2.name, f2.name = @name,
 f1.color = f2.color, f2.color = @color,
 f1.calories = f2.calories, f2.calories = @calories
WHERE (f1.id, f2.id) = (2, 5);
下面是另一个使用虚拟id值的解决方案:

UPDATE fruit SET id = 0 WHERE id = 5;
UPDATE fruit SET id = 5 WHERE id = 2;
UPDATE fruit SET id = 2 WHERE id = 0;

可以使用连接不等式来排列要交换的行:

update fruit a
 inner join fruit b on a.id <> b.id
   set a.color = b.color,
       a.name = b.name,
       a.calories = b.calories
 where a.id in (2,5) and b.id in (2,5)

如果您的操作基于ID,并且您希望交换整行,交换唯一ID的一种奇特方法是将它们编号为1,并使用0作为临时值


执行此操作的另一种方法是使用无符号列,并使用指定值,即:-1表示临时值。我并不推荐后者,因为这种方法实际上是在浪费空间。有关更多详细信息,请参阅。

与几乎任何其他编程语言中的任何其他交换操作一样。将记录1的数据复制到临时存储器中,将记录2的数据复制到记录1中。然后将数据从临时存储器复制到记录2中。sql中没有内置的“交换”操作,无法在一个整洁的查询中执行您想要的操作。或者编写一个脚本,执行与@MarcB的注释相同的操作。临时存储是否可以是表中的新行?我需要确保在完成复制操作时删除该行,尽管它可以是您想要的任何内容。在这些记录之间复制数据时,您只需要一个位置来存储其中至少一个记录。不过,我不会在同一张表中使用记录。突然,你会得到一个重复的记录,比如苹果的记录,丢掉所有的计数/库存等。。暂时存在临时记录。如果它是表中的新行,那么我猜每次都必须为它找到一个唯一的id,这就是为什么编写脚本会使它更简单,或者像@MarcB建议的那样,把它放在另一个地方。这是一个很好的方法:@fthiella beautifuly:交换我用a.color=b.color,b.color=a.color尝试过的两个值,结果出乎意料地成功了。sql不需要与普通编程语言相反的中间变量是正常的,还是只是一种特殊情况?@xtian看一下更新后的fiddle。请注意,可以将更新重新写入select语句。运行该select时,您应该看到确实存在一个中间变量,其形式为生成的表输出,其中包含用于原始值的列和用于交换值的列。这是update语句写入目标表时将从中执行的源。因此,它与普通编程语言没有什么不同。您的中间变量隐含在更新表达式本身中。@cocogorilla谢谢。我很欣赏你复杂的想法。我试过这个,但得到了两行相同的。在fthiella的回答中,“In”的id是镜像的,但在这里它们是相同的方式。