174

I am importing data from a table which has raw feeds in Varchar, I need to import a column in varchar into a string column. I tried using the <column_name>::integer as well as to_number(<column_name>,'9999999') but I am getting errors, as there are a few empty fields, I need to retrieve them as empty or null into the new table.

Braiam
  • 1
  • 11
  • 47
  • 78
Vijay DJ
  • 1,929
  • 3
  • 14
  • 10
  • 5
    Could you show us the error message? That would help – Frank Heikens May 09 '12 at 14:40
  • If the error is something like `Query failed: ERROR: invalid input syntax for integer: ""` see the solution using the [intval()](https://stackoverflow.com/questions/10518258/typecast-string-to-integer-postgres#60485123) function – Abel Callejo Oct 17 '20 at 00:29

11 Answers11

178

Wild guess: If your value is an empty string, you can use NULLIF to replace it for a NULL:

SELECT
    NULLIF(your_value, '')::int
Frank Heikens
  • 117,544
  • 24
  • 142
  • 135
70

You can even go one further and restrict on this coalesced field such as, for example:-

SELECT CAST(coalesce(<column>, '0') AS integer) as new_field
from <table>
where CAST(coalesce(<column>, '0') AS integer) >= 10; 
tatty
  • 766
  • 6
  • 4
  • 1
    why does coalesce need casting? – Jeremy Meek Mar 12 '22 at 21:40
  • Coalesce itself does not need casting. It only ensures '0' (a string) is returned instead of `NULL`. It is the resulting value (which is a string) that needs casting to integer, per the original question. – Nic Nilov Nov 19 '22 at 16:28
35

If you need to treat empty columns as NULLs, try this:

SELECT CAST(nullif(<column>, '') AS integer);

On the other hand, if you do have NULL values that you need to avoid, try:

SELECT CAST(coalesce(<column>, '0') AS integer);

I do agree, error message would help a lot.

vyegorov
  • 21,787
  • 7
  • 59
  • 73
30

The only way I succeed to not having an error because of NULL, or special characters or empty string is by doing this:

SELECT REGEXP_REPLACE(COALESCE(<column>::character varying, '0'), '[^0-9]*' ,'0')::integer FROM table
Abel Callejo
  • 13,779
  • 10
  • 69
  • 84
Jade Hamel
  • 1,360
  • 1
  • 15
  • 30
16

I'm not able to comment (too little reputation? I'm pretty new) on Lukas' post.

On my PG setup to_number(NULL) does not work, so my solution would be:

SELECT CASE WHEN column = NULL THEN NULL ELSE column :: Integer END
FROM table
Mike Guthrie
  • 4,029
  • 2
  • 25
  • 48
niko
  • 1,816
  • 13
  • 13
  • 1
    This should work, but it should be an exact equivalent of the less verbose `NULLIF()` approach. The standard actually defines NULLIF as a form of the CASE predicate. – kgrittn May 09 '12 at 16:13
15

If the value contains non-numeric characters, you can convert the value to an integer as follows:

SELECT CASE WHEN <column>~E'^\\d+$' THEN CAST (<column> AS INTEGER) ELSE 0 END FROM table;

The CASE operator checks the < column>, if it matches the integer pattern, it converts the rate into an integer, otherwise it returns 0

Igor Ostrovsky
  • 161
  • 1
  • 3
9

Common issue

Naively type casting any string into an integer like so

SELECT ''::integer

Often results to the famous error:

Query failed: ERROR: invalid input syntax for integer: ""

Problem

PostgreSQL has no pre-defined function for safely type casting any string into an integer.

Solution

Create a user-defined function inspired by PHP's intval() function.

CREATE FUNCTION intval(character varying) RETURNS integer AS $$

SELECT
CASE
    WHEN length(btrim(regexp_replace($1, '[^0-9]', '','g')))>0 THEN btrim(regexp_replace($1, '[^0-9]', '','g'))::integer
    ELSE 0
END AS intval;

$$
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;

Usage

/* Example 1 */
SELECT intval('9000');
-- output: 9000

/* Example 2 */
SELECT intval('9gag');
-- output: 9

/* Example 3 */
SELECT intval('the quick brown fox jumps over the lazy dog');
-- output: 0
Abel Callejo
  • 13,779
  • 10
  • 69
  • 84
  • Would fail for very large numbers. It'd work perfectly if you catch exceptions as well – jaisonDavis Jul 19 '21 at 12:45
  • @jaisonDavis the topic is about integer that's why it is expected that this solution would fail for very large numbers. You might want to consider creating a similar function to this solution eg: `bigintval()` and for that function replace anything that says `integer` and replace it with `bigint`. The fail is probably just about the [data type](https://www.postgresql.org/docs/9.5/datatype-numeric.html) limits. – Abel Callejo Jul 20 '21 at 00:47
3

you can use this query

SUM(NULLIF(conversion_units, '')::numeric)
slfan
  • 8,950
  • 115
  • 65
  • 78
1

The perfect solution for me is to use nullif and regexp_replace

SELECT NULLIF(REGEXP_REPLACE('98123162t3712t37', '[^0-9]', '', 'g'), '')::bigint;

Above solution consider the following edge cases.

  1. String and Number: only the regexp_replace function perfectly converts into integers.
SELECT NULLIF(REGEXP_REPLACE('string and 12345', '[^0-9]', '', 'g'), '')::bigint;
  1. Only string: regexp_replace converts non-string characters to empty strings; which can't cast directly to integer so use nullif to convert to null
SELECT NULLIF(REGEXP_REPLACE('only string', '[^0-9]', '', 'g'), '')::bigint;
  1. Integer range: Converting a string into integer may cause out of range for type integer error. So use bigint instead
SELECT NULLIF(REGEXP_REPLACE('98123162t3712t37', '[^0-9]', '', 'g'), '')::bigint;
Bedram Tamang
  • 3,748
  • 31
  • 27
0

And if your column has decimal points

select NULLIF('105.0', '')::decimal
Omari Victor Omosa
  • 2,814
  • 2
  • 24
  • 46
0

This works for me:

select (left(regexp_replace(coalesce('<column_name>', '0') || '', '[^0-9]', '', 'g'), 8) || '0')::integer

For easy view:

select (
    left(
        regexp_replace(
            -- if null then '0', and convert to string for regexp
            coalesce('<column_name>', '0') || '',
            '[^0-9]',
            '',
            'g'
        ),      -- remove everything except numbers
        8       -- ensure ::integer doesn't overload
    ) || '0'    -- ensure not empty string gets to ::integer
)::integer