Frage

Ich habe eine MySQL-Tabelle mit Koordinaten, die Spaltennamen sind X und Y.Ich will jetzt tauschen Sie die Werte in der Spalte in dieser Tabelle, so dass X wird Y und Y X. wirdDie offensichtliche Lösung wäre die Umbenennung der Spalten, aber ich nicht wollen, um Struktur ändert, da ich nicht unbedingt haben, Berechtigungen zu tun.

Ist das möglich zu tun UPDATE in irgendeiner Weise? UPDATE Tabelle SET X=Y, Y=X offensichtlich nicht tun, was ich will.


Edit:Bitte beachten Sie, dass meine Beschränkung auf Berechtigungen, oben erwähnt, verhindert wirksam die Verwendung von ALTER TABLE-oder andere Befehle, ändern Sie die Tabelle/Datenbank-Struktur.Umbenennen von Spalten oder neue hinzufügen, sind leider nicht Optionen.

War es hilfreich?

Lösung

Ich hatte gerade den Umgang mit der gleichen und ich fasse meine Erkenntnisse.

  1. Die UPDATE table SET X=Y, Y=X Ansatz offensichtlich nicht funktioniert, so es ' ll nur setzen Sie beide Werte auf Y.

  2. Hier ist eine Methode, die verwendet eine temporäre variable.Dank Antony aus den Kommentaren http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/ für die "NICHT NULL" zu zwicken.Ohne Sie, die Abfrage funktioniert ordnungsgemäß.Finden Sie das schema für die Tabelle am Ende des Beitrags.Diese Methode funktioniert nicht tauschen Sie die Werte, wenn einer von Ihnen NULL ist.Methode #3, die nicht über diese Einschränkung.

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

  3. Diese Methode wurde angeboten von Dipin, doch wieder die Kommentare http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/.Ich denke, es ist die elegante und saubere Lösung.Es funktioniert mit NULL und nicht-NULL-Werte.

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

  4. Ein weiterer Ansatz kam ich mit, das scheint zu funktionieren:

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

Im wesentlichen, der 1. Tabelle ist die, die immer aktualisiert und die 2. ist verwendet zu ziehen die alten Daten aus.
Beachten Sie, dass dieser Ansatz erfordert einen Primärschlüssel vorhanden sein.

Das ist mein test-schema:

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);

Andere Tipps

Sie könnte nehmen Sie die Summe und subtrahieren Sie die gegnerischen Wert unter X und Y

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

Hier ist eine Beispiel-test - (und es funktioniert auch mit negativen zahlen)

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>

Hier ist die swap durchgeführt

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>

Probieren Sie es aus !!!

Der folgende code funktioniert für alle Szenarien in meinem schnellen Test:

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

UPDATE Tabelle SET X=Y, Y=X wird tun genau das, was Sie wollen (Bearbeiten:in PostgreSQL, MySQL nicht, siehe unten).Die Werte stammen aus der alten Zeile und zugewiesen, um eine neue Kopie der gleichen Zeile dann die alte Zeile wird ersetzt.Sie nicht haben zu greifen, um die Verwendung einer temporären Tabelle eine temporäre Spalte, oder andere swap-tricks.

@D4V360:Ich sehe.Das ist schockierend und unerwartet.Ich benutze PostgreSQL und meine Antwort korrekt, funktioniert es (ich habe es versucht).Siehe die PostgreSQL-UPDATE-docs (unter Parameter-Ausdruck), wo er erwähnt, dass die Ausdrücke auf der rechten Seite der SET-Klauseln explizit die alten Werte der Spalten.Ich sehe, dass die entsprechenden MySQL UPDATE docs enthalten die Anweisung "Single-table-UPDATE-Zuweisungen sind in der Regel von Links nach rechts ausgewertet", was impliziert, das Verhalten, die Sie beschreiben.

Gut zu wissen.

Ok, also nur so zum Spaß, Sie könnten dies tun!(angenommen, Sie sind swapping string values)

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)

Ein schönes bisschen Spaß zu missbrauchen, die Links-rechts-evaluation-Prozess in MySQL.

Alternativ einfach verwenden, XOR, wenn Sie zahlen.Sie haben erwähnt, Koordinaten, so haben Sie schöne integer-Werte oder komplexe Zeichenfolgen?

Edit:Die XOR-Zeug wie das funktioniert übrigens:

update swapper set foo = foo ^ bar, bar = foo ^ bar, foo = foo ^ bar;

Zwei alternativen 1.Die Verwendung einer temporären Tabelle 2.Untersuchen die XOR-Algorithmus

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;
So etwas wie dies?

Edit:Über Greg ' s Kommentar:Nein, das funktioniert nicht:

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) Zeilen gefunden:2 Geändert:2 Warnungen:0

mysql> select * from test; +------+------+ | x | y | +------+------+ | 2 | 2 | | 4 | 4 | +------+------+ 2 rows in set (0.00 sec)

Ich glaube, ein intermediate exchange-variable ist die beste Praxis in solcher Weise:

update z set c1 = @c := c1, c1 = c2, c2 = @c

Erstens, es funktioniert immer;zweitens, es funktioniert unabhängig vom Datentyp.

Trotz der Beiden

update z set c1 = c1 ^ c2, c2 = c1 ^ c2, c1 = c1 ^ c2

und

update z set c1 = c1 + c2, c2 = c1 - c2, c1 = c1 - c2

arbeiten in der Regel nur für Datentyp Zahl durch die Art und Weise, und es ist Ihre Verantwortung, um überlauf zu verhindern, können Sie nicht verwenden, XOR zwischen signierten und unsignierten, Sie können auch nicht verwenden, Summe zum überlaufen Möglichkeit.

Und

update z set c1 = c2, c2 = @c where @c := c1

funktioniert nicht wenn c1 ist 0 oder NULL-oder null-Länge-Zeichenfolge oder nur Leerzeichen.

Müssen wir ändern es an

update z set c1 = c2, c2 = @c where if((@c := c1), true, true)

Hier die Skripte:

mysql> create table z (c1 int, c2 int)
    -> ;
Query OK, 0 rows affected (0.02 sec)

mysql> insert into z values(0, 1), (-1, 1), (pow(2, 31) - 1, pow(2, 31) - 2)
    -> ;
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|         -1 |          1 |
| 2147483647 | 2147483646 |
+------------+------------+
3 rows in set (0.02 sec)

mysql> update z set c1 = c1 ^ c2, c2 = c1 ^ c2, c1 = c1 ^ c2;
ERROR 1264 (22003): Out of range value for column 'c1' at row 2
mysql> update z set c1 = c1 + c2, c2 = c1 - c2, c1 = c1 - c2;
ERROR 1264 (22003): Out of range value for column 'c1' at row 3

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|          1 |         -1 |
| 2147483646 | 2147483647 |
+------------+------------+
3 rows in set (0.02 sec)

mysql> update z set c1 = c2, c2 = @c where @c := c1;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|         -1 |          1 |
| 2147483647 | 2147483646 |
+------------+------------+
3 rows in set (0.00 sec)

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          1 |          0 |
|          1 |         -1 |
| 2147483646 | 2147483647 |
+------------+------------+
3 rows in set (0.00 sec)

mysql> update z set c1 = @c := c1, c1 = c2, c2 = @c;
Query OK, 3 rows affected (0.02 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          0 |          1 |
|         -1 |          1 |
| 2147483647 | 2147483646 |
+------------+------------+
3 rows in set (0.00 sec)

mysql>update z set c1 = c2, c2 = @c where if((@c := c1), true, true);
Query OK, 3 rows affected (0.02 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select * from z;
+------------+------------+
| c1         | c2         |
+------------+------------+
|          1 |          0 |
|          1 |         -1 |
| 2147483646 | 2147483647 |
+------------+------------+
3 rows in set (0.00 sec)

Dies ist sicherlich funktioniert!Ich habe gerade nötig es zu tauschen Euro und SKK Preis-Spalten.:)

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

Das obige funktioniert nicht (ERROR 1064 (42000):Sie haben einen Fehler in Ihrer SQL-syntax)

Angenommen, Sie haben unterzeichnete ganze zahlen in den Spalten, Sie kann verwenden müssen, CAST(a ^ b gekennzeichnet), da das Ergebnis von der ^ - operator ist eine vorzeichenlose 64-bit-Ganzzahl in MySQL.

Im Falle hilft es jemand, hier ist die Methode, die ich verwendet, um swap die gleiche Spalte zwischen zwei gegebenen Reihen:

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

wo $1 und $2 sind die Schlüssel von zwei Zeilen und $3 ist das Ergebnis der ersten Abfrage.

Ich habe es nicht ausprobiert, aber

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

Vielleicht tun Sie es.

Mark

Sie könnte ändern Sie den Spaltennamen, aber dies ist mehr ein hack.Aber vorsichtig sein, alle Indizes, die möglicherweise auf diesen Spalten

Vertauschen von Spalten die Werte mit einzelnen Abfrage

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

cheers...!

Ich hatte bewegen Sie einfach den Wert aus einer Spalte in die andere (wie Archivierung) und reset der Wert der ursprünglichen Spalte.
Die unten (Hinweis #3 aus der akzeptierten Antwort oben) - für mich gearbeitet.

Update MyTable set X= (@temp:= X), X = 0, Y = @temp WHERE ID= 999;
CREATE TABLE Names
(
F_NAME VARCHAR(22),
L_NAME VARCHAR(22)
);

INSERT INTO Names VALUES('Ashutosh', 'Singh'),('Anshuman','Singh'),('Manu', 'Singh');

UPDATE Names N1 , Names N2 SET N1.F_NAME = N2.L_NAME , N1.L_NAME = N2.F_NAME 
WHERE N1.F_NAME = N2.F_NAME;

SELECT * FROM Names;

Dieses Beispiel swaps Startdatum und end_date für Datensätze, in denen die Datumsangaben sind falsch herum (bei der Durchführung von ETL-in a major rewrite, fand ich, dass einige start Termine, die später als Ihre Ende Termine.Unten, schlechte Programmierer!).

In situ, ich bin mit MEDIUMINTs aus Gründen der Leistung (wie die julianischen Tage, wird aber mit einem 0 root von 1900-01-01), so war ich OK mache eine Bedingung von WO mdu.start_date > mdu.end_date.

Die PKs wurden auf allen 3 Spalten einzeln (für den operativen / Indizierung von Gründen).

UPDATE monitor_date mdu
INNER JOIN monitor_date mdc
    ON mdu.register_id = mdc.register_id
    AND mdu.start_date = mdc.start_date
    AND mdu.end_date = mdc.end_date
SET mdu.start_date = mdu.end_date, mdu.end_date = mdc.start_date
WHERE mdu.start_date > mdu.end_date;

Tabellenname Kunden. sind die Felder a und b, swap-Wert von b;.

UPDATE Kunde SET a=(@temp:=a), a = b, b = @temp

Ich überprüfte dies gut funktioniert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top