Eu tenho uma tabela MySQL com coordenadas, os nomes das colunas são X e Y. Agora eu quero trocar os valores das colunas nesta tabela, para que X se torne Y e Y se torne X. A solução mais aparente seria renomear as colunas, mas eu não quero fazer alterações na estrutura, pois não tenho necessariamente permissões para fazer isso.
Isso é possível de alguma forma com UPDATE ? Tabela UPDATE SET X = Y, Y = X obviamente não fará o que eu quero.
Editar: Observe que minha restrição de permissões, mencionada acima, impede efetivamente o uso de ALTER TABLE ou outros comandos que alteram a estrutura da tabela / banco de dados. Renomear colunas ou adicionar novas infelizmente não são opções.
UPDATE table SET X = Y, Y = X
é a maneira padrão de fazer isso no SQL, apenas o MySQL se comporta mal.Respostas:
Eu apenas tive que lidar com o mesmo e vou resumir minhas descobertas.
A
UPDATE table SET X=Y, Y=X
abordagem obviamente não funciona, pois definirá os dois valores como Y.Aqui está um método que usa uma variável temporária. Agradecimentos a Antony pelos comentários de http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/ pelo ajuste "IS NOT NULL". Sem ele, a consulta funciona de forma imprevisível. Veja o esquema da tabela no final da postagem. Este método não troca os valores se um deles for NULL. Use o método nº 3 que não tem essa limitação.
UPDATE swap_test SET x=y, y=@temp WHERE (@temp:=x) IS NOT NULL;
Esse método foi oferecido por Dipin nos comentários de http://beerpla.net/2009/02/17/swapping-column-values-in-mysql/ . Eu acho que é a solução mais elegante e limpa. Ele funciona com valores NULL e não NULL.
UPDATE swap_test SET x=(@temp:=x), x = y, y = @temp;
Outra abordagem que criei parece funcionar:
UPDATE swap_test s1, swap_test s2 SET s1.x=s1.y, s1.y=s2.x WHERE s1.id=s2.id;
Essencialmente, a 1ª tabela é a que está sendo atualizada e a 2ª é usada para extrair os dados antigos.
Observe que essa abordagem exige que uma chave primária esteja presente.
Este é o meu esquema de teste:
fonte
Você pode pegar a soma e subtrair o valor oposto usando X e Y
Aqui está um teste de amostra (e funciona com números negativos)
Aqui está a troca sendo realizada
De uma chance !!!
fonte
TINYINT
ou enormes válvulas deINT
, você está certo !!!O código a seguir funciona para todos os cenários em meus testes rápidos:
fonte
UPDATE table swap_test
? Não deveria serUPDATE swap_test
?Tabela UPDATE SET X = Y, Y = X fará exatamente o que você deseja (edite: no PostgreSQL, não no MySQL, veja abaixo). Os valores são obtidos da linha antiga e atribuídos a uma nova cópia da mesma linha e, em seguida, a linha antiga é substituída. Você não precisa usar uma tabela temporária, uma coluna temporária ou outros truques de troca.
@ D4V360: Entendo. Isso é chocante e inesperado. Eu uso o PostgreSQL e minha resposta funciona corretamente lá (eu tentei). Veja os documentos UPDATE do PostgreSQL (em Parâmetros, expressão), onde ele menciona que as expressões do lado direito das cláusulas SET usam explicitamente os valores antigos das colunas. Vejo que os documentos correspondentes do MySQL UPDATE contêm a instrução "Atribuições de tabela única UPDATE geralmente são avaliadas da esquerda para a direita", o que implica o comportamento que você descreve.
Bom saber.
fonte
Ok, apenas por diversão, você poderia fazer isso! (supondo que você esteja trocando valores de sequência)
Foi divertido abusar do processo de avaliação da esquerda para a direita no MySQL.
Como alternativa, basta usar o XOR se forem números. Você mencionou coordenadas, então você tem valores inteiros adoráveis ou sequências complexas?
Edit: O material XOR funciona assim a propósito:
fonte
Eu acredito que ter uma variável de troca intermediária é a melhor prática da seguinte maneira:
Primeiro, funciona sempre; segundo, funciona independentemente do tipo de dados.
Apesar de ambos
e
estão funcionando normalmente, apenas para o tipo de dados numéricos, a propósito, e é sua responsabilidade evitar o estouro, você não pode usar o XOR entre assinado e não assinado, também não pode usar soma para a possibilidade de estouro.
E
não funcionará se c1 for 0 ou NULL ou cadeia de comprimento zero ou apenas espaços.
Precisamos mudar para
Aqui estão os scripts:
fonte
Duas alternativas 1. Use uma tabela temporária 2. Investigue o algoritmo XOR
fonte
Algo assim?Editar: Sobre o comentário de Greg: Não, isso não funciona:
fonte
Isso certamente funciona! Eu só precisava trocar as colunas de preço em euros e SKK. :)
O procedimento acima não funcionará (ERRO 1064 (42000): você possui um erro na sintaxe do SQL)
fonte
Supondo que você tenha assinado números inteiros em suas colunas, pode ser necessário usar CAST (a ^ b AS SIGNED), pois o resultado do operador ^ é um número inteiro de 64 bits não assinado no MySQL.
Caso isso ajude alguém, aqui está o método que eu usei para trocar a mesma coluna entre duas linhas:
onde $ 1 e $ 2 são as chaves de duas linhas e $ 3 é o resultado da primeira consulta.
fonte
Eu não tentei, mas
Pode fazer isso.
Marca
fonte
Você pode alterar os nomes das colunas, mas isso é mais um truque. Mas tenha cuidado com os índices que possam estar nessas colunas
fonte
O nome da tabela é cliente. os campos são aeb, troque um valor por b ;.
UPDATE customer SET a = (@ temp: = a), a = b, b = @temp
Eu verifiquei que está funcionando bem.
fonte
No SQL Server, você pode usar esta consulta:
fonte
Troca de valores de coluna usando consulta única
ATUALIZAÇÃO my_table SET a = @ tmp: = a, a = b, b = @ tmp;
Felicidades...!
fonte
Eu tive que apenas mover o valor de uma coluna para outra (como arquivar) e redefinir o valor da coluna original.
O abaixo (referência nº 3 da resposta aceita acima) funcionou para mim.
fonte
fonte
Este exemplo troca start_date e end_date por registros em que as datas são inversas (ao executar ETL em uma reescrita principal, encontrei algumas datas de início posteriores ao final datas de . Inoperantes, maus programadores!).
No local, estou usando MEDIUMINTs por motivos de desempenho (como dias Julianos, mas com uma raiz 0 de 1900-01-01), então eu estava bem fazendo uma condição de WHERE mdu.start_date> mdu.end_date .
As PKs estavam em todas as 3 colunas individualmente (por razões operacionais / de indexação).
fonte
Digamos que você queira trocar o valor do nome e do sobrenome em tb_user.
O mais seguro seria:
fonte
Você pode aplicar a consulta abaixo, funcionou perfeito para mim.
fonte