149

座標を持つ MySQL テーブルがあり、列名は X と Y です。X が Y になり、Y が X になるように、このテーブルの列の値を交換したいと思います。最も明白な解決策は、列の名前を変更することですが、私は必ずしもそれを行う権限を持っているわけではないので、構造を変更したくありません。

これは何らかの方法でUPDATEで行うことができますか? UPDATE table SET X=Y, Y=Xは明らかに私が望むことをしません。


編集: 上記の権限に対する私の制限により、テーブル/データベース構造を変更する ALTER TABLE またはその他のコマンドの使用が効果的に防止されることに注意してください。残念ながら、列の名前を変更したり、新しい列を追加したりすることはできません。

4

23 に答える 23

230

私は同じことに対処する必要がありました、そして私は私の発見を要約します。

  1. 両方の値をYに設定するだけなので、このUPDATE table SET X=Y, Y=Xアプローチは明らかに機能しません。

  2. 一時変数を使用するメソッドは次のとおりです。「ISNOTNULL」の調整について、 http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/のコメントからAntonyに感謝します。これがないと、クエリは予期せず機能します。投稿の最後にあるテーブルスキーマを参照してください。このメソッドは、値の1つがNULLの場合、値を交換しません。この制限がない方法#3を使用してください。

    UPDATE swap_test SET x=y, y=@temp WHERE (@temp:=x) IS NOT NULL;

  3. このメソッドは、 http: //beerpla.net/2009/02/17/swapping-column-values-in-mysql/のコメントでDipinによって提供されました。私はそれが最もエレガントでクリーンなソリューションだと思います。NULL値と非NULL値の両方で機能します。

    UPDATE swap_test SET x=(@temp:=x), x = y, y = @temp;

  4. 私が思いついた別のアプローチはうまくいくようです:

    UPDATE swap_test s1, swap_test s2 SET s1.x=s1.y, s1.y=s2.x WHERE s1.id=s2.id;

基本的に、1番目のテーブルは更新されるテーブルであり、2番目のテーブルは古いデータをプルするために使用されます。
このアプローチでは、主キーが存在する必要があることに注意してください。

これは私のテストスキーマです:

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);
于 2009-02-18T00:01:51.797 に答える
57

XとYを使用して、合計を取り、反対の値を引くことができます

UPDATE swaptest SET X=X+Y,Y=X-Y,X=X-Y;

これはサンプルテストです(負の数でも機能します)

mysql> use test
Database changed
mysql> drop table if exists swaptest;
Query OK, 0 rows affected (0.03 sec)

mysql> create table swaptest (X int,Y int);
Query OK, 0 rows affected (0.12 sec)

mysql> INSERT INTO swaptest VALUES (1,2),(3,4),(-5,-8),(-13,27);
Query OK, 4 rows affected (0.08 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM swaptest;
+------+------+
| X    | Y    |
+------+------+
|    1 |    2 |
|    3 |    4 |
|   -5 |   -8 |
|  -13 |   27 |
+------+------+
4 rows in set (0.00 sec)

mysql>

交換作業はこちら

mysql> UPDATE swaptest SET X=X+Y,Y=X-Y,X=X-Y;
Query OK, 4 rows affected (0.07 sec)
Rows matched: 4  Changed: 4  Warnings: 0

mysql> SELECT * FROM swaptest;
+------+------+
| X    | Y    |
+------+------+
|    2 |    1 |
|    4 |    3 |
|   -8 |   -5 |
|   27 |  -13 |
+------+------+
4 rows in set (0.00 sec)

mysql>

試してみる !!!

于 2012-07-31T21:44:28.007 に答える
42

次のコードは、私のクイック テストのすべてのシナリオで機能します。

UPDATE swap_test
   SET x=(@temp:=x), x = y, y = @temp
于 2009-02-18T18:15:37.580 に答える
12

UPDATE table SET X=Y, Y=Xは、あなたが望むことを正確に行います(編集:MySQLではなくPostgreSQLで、以下を参照)。値は古い行から取得され、同じ行の新しいコピーに割り当てられ、古い行が置き換えられます。一時テーブル、一時列、またはその他のスワップ トリックを使用する必要はありません。

@D4V360: なるほど。それは衝撃的で予想外です。私はPostgreSQLを使用していますが、私の答えはそこで正しく機能します(私は試しました)。PostgreSQL UPDATE ドキュメント(パラメーター、式の下)を参照してください。ここでは、SET 句の右側の式が列の古い値を明示的に使用することが言及されています。対応するMySQL UPDATEドキュメントには、「単一テーブルのUPDATE割り当ては通常、左から右に評価される」というステートメントが含まれていることがわかります。これは、説明した動作を意味します。

知っておくと良い。

于 2008-09-01T09:31:30.213 に答える
6

わかりました、ただの楽しみのために、これを行うことができます! (文字列値を交換していると仮定します)

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;
于 2008-09-01T11:00:32.573 に答える
4

2 つの選択肢 1. 一時テーブルを使用する 2. XOR アルゴリズムを調査する

于 2008-09-01T09:24:35.563 に答える
4

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)

于 2008-09-01T09:25:56.467 に答える
2

これは確かに機能します!ユーロと SKK の価格列を交換するために必要でした。:)

UPDATE tbl SET X=Y, Y=@temp where @temp:=X;

上記は機能しません (エラー 1064 (42000): SQL 構文にエラーがあります)

于 2008-12-27T13:47:55.963 に答える
1

試したことはありませんが、

UPDATE tbl SET @temp=X, X=Y, Y=@temp

やるかも。

マーク

于 2008-12-22T07:36:36.077 に答える
1

列に符号付き整数があると仮定すると、MySQL では ^ 演算子の結果が符号なし 64 ビット整数であるため、CAST(a ^ b AS SIGNED) を使用する必要がある場合があります。

それが誰かを助ける場合に備えて、2つの特定の行の間で同じ列を交換するために使用した方法は次のとおりです。

SELECT BIT_XOR(foo) FROM table WHERE key = $1 OR key = $2

UPDATE table SET foo = CAST(foo ^ $3 AS SIGNED) WHERE key = $1 OR key = $2

ここで、$1 と $2 は 2 つの行のキーで、$3 は最初のクエリの結果です。

于 2008-12-22T07:21:27.013 に答える
1

列名を変更することもできますが、これはハックです。ただし、これらの列にある可能性のあるインデックスには注意してください

于 2009-08-27T22:57:02.907 に答える
1

以下のクエリを適用できます。それは私にとって完璧に機能しました。

Table name: studentname
only single column available: name


update studentnames 
set names = case names 
when "Tanu" then "dipan"
when "dipan" then "Tanu"
end;

or

update studentnames 
set names = case names 
when "Tanu" then "dipan"
else "Tanu"
end;
于 2020-07-12T12:20:53.673 に答える
0

単一クエリを使用した列値の交換

UPDATE my_table SET a=@tmp:=a, a=b, b=@tmp;

乾杯...!

于 2014-06-10T14:42:37.070 に答える
0

他の回答が指摘しているように、列 2 を処理する直前に列 1 の値をキャッシュし、両方の列が列 2 の値に設定されるため、単純なスワップは MySQL では機能しません。

MySQL では操作の順序が保証されていないため、一時変数の使用も信頼できません。

idテーブル構造を変更せずに 2 つの列を交換する唯一の安全な方法は、主キー (この場合)を必要とする内部結合を使用することです。

UPDATE table1 t1, table2 t2
SET t1.column1 = t1.column2,
    t1.column2 = t2.column1
WHERE s1.id = s2.id;

これは問題なく動作します。

于 2022-03-04T17:42:00.570 に答える
0

xがyに、yがxにあるすべての列を交換したい場合。このクエリを使用します。

UPDATE table_name SET column_name = CASE column_name WHERE 'value of col is x' THEN 'swap it to y' ELSE 'swap it to x' END;

于 2020-08-23T14:47:52.420 に答える