Cambie el tipo de campo varchar a entero: "no se puede convertir automáticamente para escribir entero"

154

Tengo una tabla pequeña y cierto campo contiene el tipo " carácter variable ". Estoy tratando de cambiarlo a " Entero " pero da un error de que no es posible la conversión.

¿Hay alguna forma de evitar esto o debería crear otra tabla y llevar los registros a ella mediante una consulta?

El campo contiene solo valores enteros.

itsols
fuente
¿Qué ALTER TABLE específico probó y cuál fue el mensaje de error específico?
mu es demasiado corto el
@muistooshort Intenté usar alter de phppgadmin. Seleccioné la columna e intenté ingresar el nuevo tipo de campo. El error es:SQL error: ERROR: column "MID" cannot be cast to type integer
itsols
3
Primero es hacer una copia de seguridad de la tabla. Luego puede crear otra columna (por ejemplo, campo2) de tipo entero en la misma tabla. Seleccione el valor de conversión al número entero del campo1 en campo2. Luego cambie el nombre de la columna.
Igor
@Igor pero la nueva columna cae al final de la tabla ¿verdad? ¿No puedo tenerlo en la misma posición?
itsols el
2
@itsols Preocuparse por las posiciones de las columnas suele ser un signo de diseño dudoso de la aplicación. Casi siempre desea utilizar columnas y SELECTlistas con nombres explícitos , sin depender de las posiciones ordinales de las columnas. Dicho esto, el enfoque dado en las respuestas preservará la posición de la columna.
Craig Ringer el

Respuestas:

264

No hay conversión implícita (automática) desde texto varcharhacia integer(es decir, no puede pasar un varchara una función esperando integero asignar un varcharcampo a integeruno), por lo que debe especificar una conversión explícita utilizando ALTER TABLE ... ALTER COLUMN ... TYPE. .. USANDO :

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

Tenga en cuenta que puede tener espacios en blanco en sus campos de texto; en ese caso, use:

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

para quitar espacios en blanco antes de convertir.

Esto debería ser obvio por un mensaje de error si el comando se ejecutó psql, pero es posible que PgAdmin-III no muestre el error completo. Esto es lo que sucede si lo psqlpruebo en PostgreSQL 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        

Gracias @muistooshort por agregar el USING enlace.

Ver también esta pregunta relacionada ; se trata de migraciones de Rails, pero la causa subyacente es la misma y se aplica la respuesta.

Si el error persiste, puede estar relacionado no con los valores de la columna, pero los índices sobre esta columna o los valores predeterminados de la columna pueden fallar en la conversión de texto. Los índices deben descartarse antes de ALTERAR COLUMNA y recrearse después. Los valores predeterminados deben cambiarse adecuadamente.

Craig Ringer
fuente
Gracias por tomarse el tiempo. Pero parece que no puedo hacer que esto funcione. Probé su línea ALTER y me da un error "Error de sintaxis cerca del uso"
itsols
Mi declaración: ALTER TABLE "tblMenus" ALTER COLUMN "MID" USING (trim ("MID") :: integer);
itsols
1
@itsols Completamente mi error; Lo corregí justo cuando vi tu comentario. Ver revisado. Estaba justo en el código de demostración, solo que no era el ejemplo genérico al principio.
Craig Ringer
¡Un millón de gracias! Esta respuesta me ahorró muchos problemas y tiempo. Me pregunto por qué niether phppgadmin ni pgadmin tienen esto como una característica ...
itsols
@itsols La mayoría del equipo central no está tan interesado en PgAdmin, y pocos de ellos lo usan. Tiene algunas verrugas de usabilidad molestas y limitaciones de funcionalidad. Este es solo uno de muchos de ellos. Debido a que pocos expertos usan PgAdmin, no están tan motivados para arreglar las cosas que los molestarían. No lo uso yo mismo, porque me parece psqlmucho más rápido y fácil. Hace un tiempo escribí un poco sobre la usabilidad de PgAdmin con respecto a la copia de seguridad y restauración: blog.ringerc.id.au/2012/05/…
Craig Ringer
70

Esto funcionó para mí.

cambiar la columna varchar a int

change_column :table_name, :column_name, :integer

tiene:

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

cambiado a

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
bibangamba
fuente
¿Intentaste este ejercicio con datos y tus datos estaban intactos?
itsols
3
siempre y cuando lo que está en la columna es un entero, sí
bibangamba
No funciona conmigo Estoy usando ruby ​​2.2.3 con rieles 4.2.3
Thinh D. Bui
@ ThinhD.Bui - Funciona para mí, 2.3.0, rieles 4.2.6
Philip
1
Tenga cuidado con los valores predeterminados también
Francisco Quintero
17

Puedes hacerlo como:

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

o prueba esto:

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

Si está interesado en obtener más información sobre este tema, lea este artículo: https://kolosek.com/rails-change-database-column

Nesha Zoric
fuente
8

Prueba esto, funcionará seguro.

Al escribir migraciones de Rails para convertir una columna de cadena en un entero, generalmente diría:

change_column :table_name, :column_name, :integer

Sin embargo, PostgreSQL se quejará:

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

La "pista" básicamente le dice que debe confirmar que desea que esto suceda y cómo se convertirán los datos. Solo di esto en tu migración:

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

Lo anterior imitará lo que sabe de otros adaptadores de bases de datos. Si tiene datos no numéricos, los resultados pueden ser inesperados (después de todo, se está convirtiendo en un número entero).

Subhash Chandra
fuente
Solo quería agregar un punto más que, tenga cuidado con change_column. Es irreversible. Sugiero usar arriba y abajo en la migración para hacer esto reversible.
Mukesh Kumar Gupta
2
PG::InvalidTextRepresentation: ERROR: invalid input syntax for integer: ""se produce un error
Shaig Khaligli
6

Tengo el mismo problema. Entonces me di cuenta de que tenía un valor de cadena predeterminado para la columna que intentaba modificar. Al eliminar el valor predeterminado, el error desapareció :)

Valdenir Antoglioli Junior
fuente
También los índices existentes en esta columna pueden ser un problema. Deben dejarse caer antes de ALTERAR y recrearse después.
Envek
1

Si accidentalmente o no mezcló números enteros con datos de texto, primero debe ejecutar el siguiente comando de actualización (si no arriba, la tabla alter fallará):

UPDATE the_table SET col_name = replace(col_name, 'some_string', '');
webrama.pl
fuente
3
Estarías mejor con algo como regexp_replace(col_name, '[^0-9.]','','g') si está tratando de quitar caracteres no deseados y espacios en blanco. Se necesitaría algo un poco más sofisticado si se desea conservar NaNy Infe 10E42notación científica, sin embargo.
Craig Ringer
1

Si está trabajando en un entorno de desarrollo (o en el entorno de producción, puede ser una copia de seguridad de sus datos), primero borre los datos del campo DB o establezca el valor en 0.

UPDATE table_mame SET field_name= 0;

Después de eso para ejecutar la consulta a continuación y después de ejecutar con éxito la consulta, a la migración de esquema y luego ejecutar el script de migración.

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

Creo que te ayudará.

Sandip Rajput
fuente
0

Tuve el mismo problema. Empecé a restablecer el valor predeterminado de la columna.

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