Altere o tipo de campo varchar para inteiro: "não pode ser convertido automaticamente para o tipo inteiro"

154

Eu tenho uma tabela pequena e um determinado campo contém o tipo " caractere variável ". Estou tentando alterá-lo para " Inteiro ", mas dá um erro que a conversão não é possível.

Existe uma maneira de contornar isso ou devo apenas criar outra tabela e trazer os registros para ele usando uma consulta.

O campo contém apenas valores inteiros.

itsols
fonte
Qual ALTER TABLE específica você tentou e qual foi a mensagem de erro específica?
mu é muito curta
@muistooshort Tentei usar o alter do phppgadmin. Selecionou a coluna e tentou inserir o novo tipo de campo. O erro é:SQL error: ERROR: column "MID" cannot be cast to type integer
itsols
3
Primeiro é fazer backup da tabela. Em seguida, você pode criar outra coluna (digamos campo2) do tipo inteiro na mesma tabela. Selecione a conversão para o valor inteiro do campo1 no campo2. Renomeie a coluna.
Igor
@ Igor, mas a nova coluna cai no final da tabela, certo? Não posso tê-lo na mesma posição?
#
2
@itsols Importar-se com as posições das colunas geralmente é um sinal de design de aplicativo duvidoso. Você quase sempre deseja usar colunas e SELECTlistas nomeadas explicitamente , sem depender das posições ordinais das colunas. Dito isto, a abordagem dada nas respostas preservará a posição da coluna.
Craig Ringer

Respostas:

264

Não há conversão implícita (automática) de textou varcharpara integer(ou seja, você não pode passar a varcharpara uma função esperando integerou atribuir um varcharcampo a uma integer), portanto, você deve especificar uma conversão explícita usando ALTER TABLE ... ALTER COLUMN ... TYPE. .. USANDO :

ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (col_name::integer);

Observe que você pode ter espaços em branco nos seus campos de texto; nesse caso, use:

ALTER TABLE the_table ALTER COLUMN col_name TYPE integer USING (trim(col_name)::integer);

para remover o espaço em branco antes da conversão.

Isso deve ser óbvio em uma mensagem de erro se o comando foi executado psql, mas é possível que o PgAdmin-III não esteja mostrando o erro completo. Aqui está o que acontece se eu testá-lo no psqlPostgreSQL 9.2:

=> CREATE TABLE test( x varchar );
CREATE TABLE
=> insert into test(x) values ('14'), (' 42  ');
INSERT 0 2
=> ALTER TABLE test ALTER COLUMN x TYPE integer;
ERROR:  column "x" cannot be cast automatically to type integer
HINT:  Specify a USING expression to perform the conversion. 
=> ALTER TABLE test ALTER COLUMN x TYPE integer USING (trim(x)::integer);
ALTER TABLE        

Obrigado @muistooshort por adicionar o USINGlink.

Veja também esta questão relacionada ; trata-se de migrações do Rails, mas a causa subjacente é a mesma e a resposta se aplica.

Se o erro ainda ocorrer, ele pode estar relacionado não aos valores da coluna, mas os índices nessa coluna ou nos valores padrão da coluna podem falhar na conversão de tipo. Os índices precisam ser eliminados antes de ALTER COLUMN e recriados depois. Os valores padrão devem ser alterados adequadamente.

Craig Ringer
fonte
Obrigado por tomar o tempo. Mas parece que não consigo fazer isso funcionar. Tentei sua linha ALTER e dá-me um erro "Erro de sintaxe próximo Usando"
itsols
Minha declaração: ALTER TABLE "tblMenus" ALTER COLUMN "MID" USING (trim ("MID") :: integer);
itsols
1
@itsols Totalmente meu erro; Corrigi-o assim como vi seu comentário. Veja revisado. Estava certo no código de demonstração, mas não no exemplo genérico no início.
Craig Ringer
Graças um milhão! Essa resposta me salvou muitos problemas e tempo. Eu me pergunto por phppgadmin niether nem pgadmin ter isso como uma característica ...
itsols
@itsols A maior parte da equipe principal não está interessada no PgAdmin e poucos o usam. Possui algumas verrugas de usabilidade e limitações de funcionalidade irritantes. Este é apenas um de muitos deles. Como poucos especialistas usam o PgAdmin, eles não estão tão motivados para consertar as coisas que os incomodariam. Eu não uso, porque acho psqlmuito mais rápido e fácil. Eu escrevi um pouco de um discurso retórico sobre PgAdmin usabilidade com relação ao backup e restaurar um tempo atrás: blog.ringerc.id.au/2012/05/...
Craig Ringer
70

isso funcionou para mim.

alterar coluna varchar para int

change_column :table_name, :column_name, :integer

obteve:

PG::DatatypeMismatch: ERROR:  column "column_name" cannot be cast automatically to type integer
HINT:  Specify a USING expression to perform the conversion.

ligado a

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
bibangamba
fonte
você tentou este exercício com dados e seus dados estavam intactos?
itsols
3
enquanto o que está na coluna é um inteiro, sim
bibangamba
Isso não funciona comigo. Estou usando o ruby ​​2.2.3 com trilhos 4.2.3
Thinh D. Bui
@ ThinhD.Bui - funciona para mim, 2.3.0, 4.2.6 trilhos
Philip
1
Tenha cuidado com padrões bem
Francisco Quintero
17

Você pode fazê-lo como:

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'

ou tente o seguinte:

change_column :table_name, :column_name, :integer, using: 'column_name::integer'

Se você estiver interessado em saber mais sobre este tópico, leia este artigo: https://kolosek.com/rails-change-database-column

Nesha Zoric
fonte
8

Tente isso, ele funcionará com certeza.

Ao escrever migrações do Rails para converter uma coluna de string em um número inteiro, você costuma dizer:

change_column :table_name, :column_name, :integer

No entanto, o PostgreSQL irá reclamar:

PG::DatatypeMismatch: ERROR:  column "column_name" cannot be cast automatically to type integer
HINT:  Specify a USING expression to perform the conversion.

A "dica" basicamente informa que você precisa confirmar que deseja que isso aconteça e como os dados serão convertidos. Apenas diga isso em sua migração:

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'

O acima irá imitar o que você sabe de outros adaptadores de banco de dados. Se você tiver dados não numéricos, os resultados podem ser inesperados (mas você está convertendo para um número inteiro).

Subhash Chandra
fonte
Eu só queria acrescentar mais um ponto que, tenha cuidado com change_column. é irreversível. Eu sugiro usar a migração para cima e para baixo para tornar isso reversível.
Mukesh Kumar Gupta
2
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: ""erro acontece
Shaig Khaligli
6

Eu tenho o mesmo problema. Do que percebi, eu tinha um valor de string padrão para a coluna que estava tentando alterar. A remoção do valor padrão fez com que o erro desaparecesse :)

Valdenir Antoglioli Junior
fonte
Os índices existentes nesta coluna também podem ser um problema. Eles precisam ser descartados antes de ALTER e recriados depois.
Envek
1

Se você acidentalmente ou não misturou números inteiros com dados de texto, deve executar primeiro o comando abaixo de atualização (se não estiver acima da tabela de alteração falhará):

UPDATE the_table SET col_name = replace(col_name, 'some_string', '');
webrama.pl
fonte
3
Você seria melhor com algo como regexp_replace(col_name, '[^0-9.]','','g')se estivesse tentando retirar caracteres indesejados e espaços em branco. Você precisa de algo um pouco mais sofisticado, se você deseja manter NaNe Infe 10E42notação científica, no entanto.
Craig Ringer
1

Se você estiver trabalhando no ambiente de desenvolvimento (ou no ambiente de produção, pode fazer backup dos seus dados), primeiro limpe os dados do campo DB ou defina o valor como 0.

UPDATE table_mame SET field_name= 0;

Depois disso, execute a consulta abaixo e depois execute com êxito a consulta, para a migração de esquema e depois execute o script de migração.

ALTER TABLE table_mame ALTER COLUMN field_name TYPE numeric(10,0) USING field_name::numeric;

Eu acho que isso vai te ajudar.

Sandip Rajput
fonte
0

Eu tive o mesmo problema. Comecei a redefinir o padrão da coluna.

change_column :users, :column_name, :boolean, default: nil
change_column :users, :column_name, :integer, using: 'column_name::integer', default: 0, null: false
Maxime Boué
fonte