在MySQL中交换列值
我有一个带有坐标的MySQL表,列名称为X和Y。现在我想交换该表中的列值,以使X变为Y而Y变为X。最明显的解决方案是重命名列,但是我不想进行结构更改,因为我不一定有这样做的权限。
这可能以某种方式与UPDATE有关吗?更新表SET X = Y,Y = X显然不会满足我的要求。
编辑:请注意,我上面提到的权限限制有效地防止了使用ALTER TABLE或者其他更改表/数据库结构的命令。不幸的是,重命名列或者添加新列不是选项。
解决方案
回答
两种选择
1.使用临时表
2.调查
XOR算法
回答
`
ALTER TABLE table ADD COLUMN tmp; UPDATE table SET tmp = X; UPDATE table SET X = Y; UPDATE table SET Y = tmp; ALTER TABLE table DROP COLUMN tmp;
像这样吗?
编辑:关于格雷格的评论:
不,这不起作用:
mysql> select * from test; +------+------+ | x | y | +------+------+ | 1 | 2 | | 3 | 4 | +------+------+ 2 rows in set (0.00 sec) mysql> update test set x=y, y=x; Query OK, 2 rows affected (0.00 sec) Rows matched: 2 Changed: 2 Warnings: 0 mysql> select * from test; +------+------+ | x | y | +------+------+ | 2 | 2 | | 4 | 4 | +------+------+ 2 rows in set (0.00 sec)
回答
UPDATE表SET X = Y,Y = X将完全满足要求(编辑:在PostgreSQL中,而不是MySQL,请参见下文)。这些值取自旧行,并分配给同一行的新副本,然后替换旧行。我们不必求助于使用临时表,临时列或者其他交换技巧。
@ D4V360:我知道了。这是令人震惊和始料未及的。我使用PostgreSQL,我的答案在那里正确工作(我尝试过)。请参见PostgreSQL UPDATE文档(在Parameters(表达式)下),其中提到SET子句右侧的表达式显式使用列的旧值。我看到相应的MySQL UPDATE文档包含语句"通常从左到右评估单表UPDATE分配",这表示我们描述的行为。
很高兴知道。
回答
好的,所以只是为了好玩,我们可以这样做! (假设我们要交换字符串值)
mysql> select * from swapper; +------+------+ | foo | bar | +------+------+ | 6 | 1 | | 5 | 2 | | 4 | 3 | +------+------+ 3 rows in set (0.00 sec) mysql> update swapper set -> foo = concat(foo, "###", bar), -> bar = replace(foo, concat("###", bar), ""), -> foo = replace(foo, concat(bar, "###"), ""); Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0 mysql> select * from swapper; +------+------+ | foo | bar | +------+------+ | 1 | 6 | | 2 | 5 | | 3 | 4 | +------+------+ 3 rows in set (0.00 sec)
滥用MySQL中从左到右的评估过程会带来很多乐趣。
另外,如果它们是数字,则只需使用XOR。我们提到了坐标,那么我们有可爱的整数值还是复杂的字符串?
编辑:XOR东西的方式是这样的:
update swapper set foo = foo ^ bar, bar = foo ^ bar, foo = foo ^ bar;
回答
假设列中有带符号的整数,则可能需要使用CAST(a ^ b AS SIGNED),因为^运算符的结果是MySQL中无符号的64位整数。
万一它对任何人都有帮助,这是我用来在两个给定行之间交换同一列的方法:
SELECT BIT_XOR(foo) FROM table WHERE key = OR key = UPDATE table SET foo = CAST(foo ^ AS SIGNED) WHERE key = OR key =
其中$ 1和$ 2是两行的键,而$ 3是第一个查询的结果。
回答
我没有尝试过
UPDATE tbl SET @temp=X, X=Y, Y=@temp
可能会做。
标记
回答
这肯定有效!我只是需要它来交换欧元和SKK价格栏。 :)
UPDATE tbl SET X=Y, Y=@temp where @temp:=X;
上面的方法不起作用(错误1064(42000):SQL语法有错误)
回答
我只需要处理相同的问题,然后我将总结我的发现。
- UPDATE表SET X = Y,Y = X`的方法显然不起作用,因为它将两个值都设置为Y。
- 这是使用临时变量的方法。感谢http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/的注释中的" IS NOT NULL"调整。没有它,查询将无法正常工作。请参阅文章末尾的表架构。如果其中一个为NULL,则此方法不交换值。使用没有此限制的方法#3. UPDATE swap_test SET x = y,y = @ temp(@temp:= x)不为空;
- Dipin在http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/的注释中再次提供了此方法。我认为这是最优雅,最干净的解决方案。它适用于NULL和非NULL值。 UPDATE swap_test SET x =(@ temp:= x),x = y,y = @temp;`
- 我想出的另一种方法似乎可行:
UPDATE swap_test s1,swap_test s2 SET s1.x = s1.y,s1.y = s2.x WHERE s1.id = s2.id;
本质上,第一个表是要更新的表,第二个表是用于从中提取旧数据的表。
请注意,此方法要求显示主键。
这是我的测试架构:
CREATE TABLE `swap_test` ( `id` int(11) NOT NULL AUTO_INCREMENT, `x` varchar(255) DEFAULT NULL, `y` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; INSERT INTO `swap_test` VALUES ('1', 'a', '10'); INSERT INTO `swap_test` VALUES ('2', NULL, '20'); INSERT INTO `swap_test` VALUES ('3', 'c', NULL);
回答
以下代码适用于我的快速测试中的所有方案:
UPDATE table swap_test SET x=(@temp:=x), x = y, y = @temp
回答
我们可以更改列名,但这更像是一个技巧。但请注意这些列上可能包含的任何索引