Mam tabelę MySQL ze współrzędnymi, nazwy kolumn to X i Y. Teraz chcę zamienić wartości kolumn w tej tabeli, tak aby X stało się Y, a Y stało się X. Najbardziej oczywistym rozwiązaniem byłaby zmiana nazw kolumn, ale ja nie chcę wprowadzać zmian w strukturze, ponieważ niekoniecznie mam do tego uprawnienia.
Czy można to w jakiś sposób zrobić z UPDATE ? UPDATE table SET X = Y, Y = X oczywiście nie zrobi tego, co chcę.
Edycja: Należy pamiętać, że wspomniane powyżej moje ograniczenie uprawnień skutecznie uniemożliwia użycie ALTER TABLE lub innych poleceń zmieniających strukturę tabeli / bazy danych. Zmiana nazw kolumn lub dodanie nowych nie jest niestety opcją.
UPDATE table SET X = Y, Y = X
jest to standardowy sposób robienia tego w SQL, tylko MySQL źle się zachowuje.Odpowiedzi:
Po prostu musiałem poradzić sobie z tym samym i podsumuję moje ustalenia.
To
UPDATE table SET X=Y, Y=X
podejście oczywiście nie działa, ponieważ ustawi obie wartości na Y.Oto metoda wykorzystująca zmienną tymczasową. Podziękowania dla Antony'ego za komentarze http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/ za poprawkę „NIE JEST NULL”. Bez tego zapytanie działa nieprzewidywalnie. Zobacz schemat tabeli na końcu postu. Ta metoda nie zamienia wartości, jeśli jedna z nich ma wartość NULL. Użyj metody nr 3, która nie ma tego ograniczenia.
UPDATE swap_test SET x=y, y=@temp WHERE (@temp:=x) IS NOT NULL;
Ta metoda została zaproponowana przez Dipina w komentarzach http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/ . Myślę, że to najbardziej eleganckie i czyste rozwiązanie. Działa zarówno z wartościami NULL, jak i innymi niż NULL.
UPDATE swap_test SET x=(@temp:=x), x = y, y = @temp;
Inne podejście, które wymyśliłem, wydaje się działać:
UPDATE swap_test s1, swap_test s2 SET s1.x=s1.y, s1.y=s2.x WHERE s1.id=s2.id;
Zasadniczo pierwsza tabela jest aktualizowana, a druga służy do pobierania starych danych.
Należy pamiętać, że to podejście wymaga obecności klucza podstawowego.
Oto mój schemat testu:
źródło
Możesz wziąć sumę i odjąć przeciwną wartość za pomocą X i Y
Oto przykładowy test (działa z liczbami ujemnymi)
Oto wykonywana zamiana
Spróbuj !!!
źródło
TINYINT
lub ogromne wartościINT
, masz rację !!!Poniższy kod działa dla wszystkich scenariuszy w moim szybkim testowaniu:
źródło
UPDATE table swap_test
? Nie powinnoUPDATE swap_test
?UPDATE table SET X = Y, Y = X zrobi dokładnie to, co chcesz (edycja: w PostgreSQL, nie w MySQL, patrz poniżej). Wartości są pobierane ze starego wiersza i przypisywane do nowej kopii tego samego wiersza, a następnie zastępowany jest stary wiersz. Nie musisz uciekać się do korzystania z tymczasowej tabeli, tymczasowej kolumny ani innych sztuczek wymiany.
@ D4V360: Rozumiem. To szokujące i nieoczekiwane. Używam PostgreSQL i moja odpowiedź tam działa poprawnie (próbowałem). Zobacz dokumentację PostgreSQL UPDATE (w części Parametry, wyrażenie), gdzie wspomniano, że wyrażenia po prawej stronie klauzul SET jawnie używają starych wartości kolumn. Widzę, że odpowiednie dokumenty MySQL UPDATE zawierają stwierdzenie „Przypisania aktualizacji w pojedynczej tabeli są generalnie oceniane od lewej do prawej”, co sugeruje zachowanie, które opisujesz.
Dobrze wiedzieć.
źródło
Ok, więc dla zabawy możesz to zrobić! (zakładając, że zamieniasz wartości ciągów)
Niezła zabawa nadużywając procesu oceny od lewej do prawej w MySQL.
Alternatywnie, po prostu użyj XOR, jeśli są to liczby. Wspomniałeś o współrzędnych, więc czy masz urocze wartości całkowite lub złożone ciągi?
Edycja: rzeczy XOR działają tak przy okazji:
źródło
Uważam, że posiadanie pośredniej zmiennej wymiany jest najlepszą praktyką w taki sposób:
Po pierwsze, działa zawsze; po drugie, działa niezależnie od typu danych.
Pomimo obu
i
działają zwykle, nawiasem mówiąc, tylko dla typu danych liczbowych, a Twoim obowiązkiem jest zapobieganie przepełnieniu, nie możesz używać XOR między podpisanymi a niepodpisanymi, nie możesz również użyć sumy do przepełnienia.
I
nie działa, jeśli c1 jest równe 0 lub NULL, ciąg znaków o zerowej długości lub tylko spacje.
Musimy to zmienić na
Oto skrypty:
źródło
Dwie alternatywy 1. Użyj tabeli tymczasowej 2. Zbadaj algorytm XOR
źródło
Coś takiego?Edycja: O komentarzu Grega: Nie, to nie działa:
źródło
To na pewno działa! Potrzebowałem go tylko do zamiany kolumn cen w Euro i SKK. :)
Powyższe nie zadziała (ERROR 1064 (42000): masz błąd w składni SQL)
źródło
Zakładając, że w kolumnach znajdują się liczby całkowite ze znakiem, może być konieczne użycie funkcji CAST (a ^ b AS SIGNED), ponieważ wynikiem operatora ^ jest 64-bitowa liczba całkowita bez znaku w MySQL.
Na wypadek, gdyby to komuś pomogło, oto metoda, której użyłem do zamiany tej samej kolumny między dwoma podanymi wierszami:
gdzie $ 1 i $ 2 to klucze dwóch wierszy, a $ 3 to wynik pierwszego zapytania.
źródło
Nie próbowałem tego, ale
Może to zrobić.
znak
źródło
Państwo mogłoby zmienić nazwy kolumn, ale to jest bardziej hack. Uważaj jednak na indeksy, które mogą znajdować się w tych kolumnach
źródło
Nazwa tabeli to customer. pola to a i b, zamień wartość na b ;.
AKTUALIZUJ SET klienta a = (@ temp: = a), a = b, b = @temp
Sprawdziłem, że to działa dobrze.
źródło
W SQL Server możesz użyć tego zapytania:
źródło
Zamiana wartości kolumn za pomocą pojedynczego zapytania
UPDATE my_table SET a = @ tmp: = a, a = b, b = @ tmp;
Twoje zdrowie...!
źródło
Musiałem po prostu przenieść wartość z jednej kolumny do drugiej (jak archiwizacja) i zresetować wartość oryginalnej kolumny.
Poniższe (odniesienie nr 3 z zaakceptowanej odpowiedzi powyżej) zadziałało dla mnie.
źródło
źródło
Ten przykład swapy START_DATE i END_DATE dla rekordów, gdzie terminy są w niewłaściwy sposób okrągłe (przy wykonywaniu ETL do poważnej przepisać, znalazłem pewne początkowe daty później niż ich koniec daty . Dół, źli programiści!).
Na miejscu używam MEDIUMINT ze względu na wydajność (jak dni juliańskie, ale mając 0 root z 1900-01-01), więc byłem OK, wykonując warunek GDZIE mdu.start_date> mdu.end_date .
PK znajdowały się na wszystkich 3 kolumnach indywidualnie (ze względów operacyjnych / indeksacyjnych).
źródło
Powiedzmy, że chcesz zamienić wartość imienia i nazwiska w tb_user.
Najbezpieczniejsze byłoby:
źródło
Możesz złożyć poniższe zapytanie, dla mnie zadziałało idealnie.
źródło