Posso renomear os valores em uma coluna MySQL ENUM em uma consulta?


12

Suponha que eu tenha uma tabela de banco de dados com um ENUM('value_one','value_two'). Eu quero mudar isso para um ENUM('First value','Second value'). Atualmente, estou fazendo o seguinte:

ALTER TABLE `table` MODIFY `column` ENUM('value_one','value_two','First value','Second value');
UPDATE `table` SET `column`='First Value' WHERE `column`='value_one';
UPDATE `table` SET `column`='Second Value' WHERE `column`='value_two';
ALTER TABLE `table` MODIFY `column` ENUM('First value','Second value');

Existe uma maneira mais eficiente de fazer isso, por exemplo, uma maneira de conseguir isso com uma única ALTER TABLE declaração?

Respostas:


10

A técnica a seguir, que estou prestes a mostrar, exigirá tripas de aço.

Dados os seguintes critérios

  • datadir é /var/lib/mysql
  • mesa é mydb.mytb
  • coluna enum chamada é chamada enum_col
  • engine is MyISAM

Aqui está uma rachadura que desafia a morte:

  1. CREATE TABLE mydb.mybt LIKE mydb.mytb;

  2. ALTER TABLE mydb.mybt MODIFY enum_col ENUM('First value','Second value');

  3. SET wait_timeout=86400; SET interactive_timeout=86400;

  4. FLUSH TABLES WITH READ LOCK;

  5. Em uma sessão OS / SSH separada, troque os arquivos .frm

    • $ mv /var/lib/mysql/mydb/mytb.frm /var/lib/mysql/mydb/myxx.frm
    • $ mv /var/lib/mysql/mydb/mybt.frm /var/lib/mysql/mydb/mytb.frm
    • $ mv /var/lib/mysql/mydb/myxx.frm /var/lib/mysql/mydb/mybt.frm
  6. UNLOCK TABLES;

  7. DROP TABLE mydb.mybt;

É isso aí !!!

CAVEAT: NÃO POSSO TER CRÉDITO POR ISSO!

Essa técnica vem de "MySQL de alto desempenho: otimização, backups, replicação e muito mais", páginas 146-148 no subtítulo Acelerando a tabela ALTER TABLE . O parágrafo 1 diz:

A técnica que estamos prestes a demonstrar não é suportada, não documentada e pode não funcionar. Use-o por sua conta e risco. Aconselhamos que você faça backup dos seus dados primeiro!

De uma chance ! (Por favor, deixe-nos saber como ficou)

UPDATE 2011-10-05 17:49 EDT

Se a tabela for MyISAM e você tiver espaço suficiente na produção e uma janela de tempo de inatividade direta, tente o seguinte:

  1. service mysql restart --skip-networking

  2. Em uma sessão OS / SSH separada, faça uma cópia da tabela

    • cp /var/lib/mysql/mydb/mytb.frm /var/lib/mysql/mydb/mytbplay.frm
    • cp /var/lib/mysql/mydb/mytb.MYD /var/lib/mysql/mydb/mytbplay.MYD
    • cp /var/lib/mysql/mydb/mytb.MYI /var/lib/mysql/mydb/mytbplay.MYI

INFORMATION_SCHEMA.TABLESdetectará automaticamente a presença da nova tabela chamada mydb.mytbplay.

  1. Execute o algoritmo de tripas de aço em mydb.mytbplay

  2. Você testa a integridade de mydb.mytbplay

Se você está satisfeito

  1. ALTER TABLE mydb.mytb RENAME mydb.mytb_backup;

  2. ALTER TABLE mydb.mytbplay RENAME mydb.mytb;

  3. service mysql restart

De uma chance!


+1 para uma resposta engenhosa! No entanto, não tentarei fazer com que você saiba como ficou a pergunta, pois a pergunta se refere a um script de atualização para todos os bancos de dados de produção ao vivo do meu cliente ;-) No entanto, posso tentar isso em um ambiente de desenvolvimento apenas para se divertir. Mas com esse aviso, eu nunca executaria isso na produção!
Josh

3

Uma solução simples seria:

1- adicione uma nova coluna:

ALTER TABLE `table` ADD `enum2` ENUM('First value', 'Second value') NOT NULL AFTER `enum`;

2- Copie o valor da coluna para enum2 com substituições:

UPDATE `table` SET enum2=REPLACE(`column`, "value_one", "new value")

3- Solte a coluna column, renomeie enumpara column.

OBSERVAÇÃO : nesta pergunta, em 05/10/2011, minha solução é válida para MYSQL 4.1 e mais recente (AFAIK)


Embora isso pareça uma boa solução (e não tão estressante quanto a resposta aceita!), Vale a pena notar que a etapa 3 exige pelo menos uma ALTER TABLEdeclaração, e o OP estava procurando por algo que exigisse apenas uma. Novamente, dito isso, parece uma solução sólida e perfeitamente padrão.
RDFozz
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.