219

I have a small table and a certain field contains the type "character varying". I'm trying to change it to "Integer" but it gives an error that casting is not possible.

Is there a way around this or should I just create another table and bring the records into it using a query.

The field contains only integer values.

tshepang
  • 12,111
  • 21
  • 91
  • 136
itsols
  • 5,406
  • 7
  • 51
  • 95
  • What specific ALTER TABLE did you try and what was the specific error message? – mu is too short Nov 01 '12 at 03:38
  • @muistooshort I tried using alter from phppgadmin. Selected the column and tried to input the new field type. The error is: `SQL error: ERROR: column "MID" cannot be cast to type integer` – itsols Nov 01 '12 at 03:42
  • 3
    First is to backup table. Then you may create an another column (say field2) of integer type in the same table. Select the cast to integer value of the field1 into field2 . Then rename the column. – Igor Nov 01 '12 at 03:42
  • @Igor but the new column falls at the end of the table right? Can't I have it in the same position? – itsols Nov 01 '12 at 03:43
  • yes you'll have it last. – Igor Nov 01 '12 at 03:44
  • hmm, try this one http://www.postgresonline.com/journal/archives/29-How-to-convert-a-table-column-to-another-data-type.html – Igor Nov 01 '12 at 03:48
  • 2
    @itsols Caring about column positions is usually a sign of iffy application design. You almost always want to be using explicitly named columns and `SELECT` lists, not relying on column ordinal positions. That said, the approach given in the answers will preserve column position. – Craig Ringer Nov 01 '12 at 03:51

9 Answers9

352

There is no implicit (automatic) cast from text or varchar to integer (i.e. you cannot pass a varchar to a function expecting integer or assign a varchar field to an integer one), so you must specify an explicit cast using ALTER TABLE ... ALTER COLUMN ... TYPE ... USING:

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

Note that you may have whitespace in your text fields; in that case, use:

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

to strip white space before converting.

This shoud've been obvious from an error message if the command was run in psql, but it's possible PgAdmin-III isn't showing you the full error. Here's what happens if I test it in psql on 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        

Thanks @muistooshort for adding the USING link.

See also this related question; it's about Rails migrations, but the underlying cause is the same and the answer applies.

If the error still occurs, then it may be related not to column values, but indexes over this column or column default values might fail typecast. Indexes need to be dropped before ALTER COLUMN and recreated after. Default values should be changed appropriately.

Envek
  • 4,426
  • 3
  • 34
  • 42
Craig Ringer
  • 307,061
  • 76
  • 688
  • 778
  • Thank you for taking the time. But I cannot seem to get this working. I tried your ALTER line and it gives me an error "Syntax error near Using" – itsols Nov 01 '12 at 04:08
  • My statement: ALTER TABLE "tblMenus" ALTER COLUMN "MID" USING (trim("MID")::integer); – itsols Nov 01 '12 at 04:08
  • 1
    @itsols Entirely my mistake; I corrected it just as I saw your comment. See revised. It was right in the demo code, just not the generic example at the start. – Craig Ringer Nov 01 '12 at 04:10
  • Thanks a million! This answer saved me a lot of trouble and time. I wonder why niether phppgadmin nor pgadmin have this as a feature... – itsols Nov 01 '12 at 04:21
  • @itsols Most of the core team isn't that interested in PgAdmin, and few of them use it. It has some annoying usability warts and functionality limitations. This is only one of many of them. Because few experts use PgAdmin they aren't as motivated to fix the things that would annoy them about it. I don't use it myself, because I find `psql` much quicker and easier. I wrote a bit of a rant about PgAdmin usability with regards to backup and restore a while ago: http://blog.ringerc.id.au/2012/05/postgresql-usability-pgadmin-iii-and-pg.html – Craig Ringer Nov 01 '12 at 04:24
  • Thanks for that update on your blog. Even I don't like wx and that's why I got out of CodeBlocks and switched to Lazarus. I just couldn't get wx properly working on either Ubuntu or Windows. But then again, I think Lazarus also uses it but it just works out of the box. Furthermore, I didn't like QT because of licensing and availability. Oops, this is going in a different direction ;) Thanks again! – itsols Nov 01 '12 at 04:45
  • @CraigRinger I was reading some other answer of yours, and asked you here by mistake.. Damnn!! Sorry :p – Arup Rakshit Jun 30 '14 at 12:41
  • I tried this and it didn't work when the table didn't even have any rows at all. – CMCDragonkai Dec 16 '15 at 13:21
  • Be careful with executing this in PostgresSQL as i had ran that code and it stated it was successful, but when i looked at the table structure.... nothing had changed. In my case I'm in a position to drop and re-create the table. – JayRizzo May 30 '17 at 19:29
  • What happens if column contains non-numeric values, like digits with letters. What happens to letters after cast? – jayarjo Feb 03 '21 at 08:52
  • @jayarjo Try it and see. `'foo'::integer` . You get an error raised. I don't recall off the top of my head if postgres has non-fatal casts, but you can pattern match the string against a regexp or `like` expression and skip the cast if it doesn't look sensible. – Craig Ringer Feb 19 '21 at 04:12
79

this worked for me.

change varchar column to int

change_column :table_name, :column_name, :integer

got:

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

chnged to

change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)'
bibangamba
  • 1,463
  • 1
  • 19
  • 23
28

You can do it like:

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

or try this:

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

If you are interested to find more about this topic read this article: https://kolosek.com/rails-change-database-column

Nesha Zoric
  • 6,218
  • 42
  • 34
9

Try this, it will work for sure.

When writing Rails migrations to convert a string column to an integer you'd usually say:

change_column :table_name, :column_name, :integer

However, PostgreSQL will complain:

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

The "hint" basically tells you that you need to confirm you want this to happen, and how data shall be converted. Just say this in your migration:

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

The above will mimic what you know from other database adapters. If you have non-numeric data, results may be unexpected (but you're converting to an integer, after all).

Subhash Chandra
  • 3,165
  • 1
  • 27
  • 30
8

I got the same problem. Than I realized I had a default string value for the column I was trying to alter. Removing the default value made the error go away :)

  • Also existing indexes on this column might be a problem. They need to be dropped before ALTER and recreated after. – Envek Nov 19 '19 at 17:29
7

I had the same issue. I started to reset the default of the column.

change_column :users, :column_name, :boolean, default: nil
change_column :users, :column_name, :integer, using: 'column_name::integer', default: 0, null: false
Maxime Boué
  • 648
  • 7
  • 10
2

If you are working on development environment(or on for production env. it may be backup your data) then first to clear the data from the DB field or set the value as 0.

UPDATE table_mame SET field_name= 0;

After that to run the below query and after successfully run the query, to the schemamigration and after that run the migrate script.

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

I think it will help you.

Mayur Shah
  • 3,344
  • 1
  • 22
  • 41
1

If you've accidentally or not mixed integers with text data you should at first execute below update command (if not above alter table will fail):

UPDATE the_table SET col_name = replace(col_name, 'some_string', '');
webrama.pl
  • 1,870
  • 1
  • 23
  • 36
  • 3
    You'd be better off with something like `regexp_replace(col_name, '[^0-9.]','','g')` if you're trying to strip unwanted characters and white-space. You'd need something a bit more sophisticated if you want to retain `NaN` and `Inf` and `10E42` scientific notation, though. – Craig Ringer Jul 25 '13 at 23:48
0

Empty Strings or Nulls in character varying

If you have a column with empty strings or nulls, you may run into the error message:

invalid input syntax for type integer: ""

Solution

use coalesce and a nullif to get empty strings and nulls to become a zero value.

ALTER TABLE peopleGroup ALTER numberPeople TYPE INT USING (cast ( coalesce( nullif( trim(numberPeople), '' ), '0' ) as integer ))
Tim G
  • 1,812
  • 12
  • 25