Thread: Type coercion on column in a query

Type coercion on column in a query

From
"Kenny Mok"
Date:
Dear all,

I am just a novice in SQL and also in PostgreSQL. I have encountered some
difficulties in developing a website using PostgreSQL as my backend
database.

My situation is, I have such a table "test" :

testing=# SELECT * from test ;id  |  data1      | data2
----+------------+-------- 1  | 2003-5-6 | 3 days 2  | 1234       | 34
(2 rows)

where columns data1 and data 2 are with data types varchar, where all my
data is stored into it.

What I want to do is to extracts the data from this database and casting it
before shown in front of my client. So, I do the following queries :

testing=# SELECT
testing-#    cast(data1 as numeric) - cast(data2 as numeric)
testing-#    as result from test
testing-#    where id = 2;
ERROR:  Cannot cast type 'character varying' to 'numeric'
testing=#
testing=# SELECT
testing-#    to_number(data1) - to_number(data2)
testing-#    as result from test
testing-#    where id = 2;
ERROR:  Function 'to_number(varchar)' does not exist       Unable to identify a function that satisfies the given
argument
types       You may need to add explicit typecasts
testing=#

It seems that using the casting function and to_number function cannot
casting the target columns into my requied type. However, when the argument
given to these functions are literals, the result is like this :

testing=# SELECT
testing-#   cast('1234' as numeric) - cast('34' as numeric)
testing-#   as result ;result
--------  1200
(1 row)

testing=# SELECT
testing-#   to_number('1234') - to_number('34')
testing-#   as result ;
ERROR:  Function 'to_number(unknown)' does not exist       Unable to identify a function that satisfies the given
argument
types       You may need to add explicit typecasts
testing=#

The casting function works as my expected while the to_number function does
not.
So, how can I cast the column into the datatype I want during querying
before shown in front of my users?? And any concept that I have
mis-understood already ?? Thanks for your help in advance.

^_^



Re: Type coercion on column in a query

From
Richard Huxton
Date:
On Thursday 08 May 2003 1:59 am, Kenny Mok wrote:
> Dear all,
>
> I am just a novice in SQL and also in PostgreSQL. I have encountered some
> difficulties in developing a website using PostgreSQL as my backend
> database.
>
> My situation is, I have such a table "test" :
>
> testing=# SELECT * from test ;
>  id  |  data1      | data2
> ----+------------+--------
>   1  | 2003-5-6 | 3 days
>   2  | 1234       | 34
> (2 rows)
>
> where columns data1 and data 2 are with data types varchar, where all my
> data is stored into it.
>
> What I want to do is to extracts the data from this database and casting it
> before shown in front of my client. So, I do the following queries :

You can see what functions are available and what types they support with \df
from the psql command-line.

=> \df numer*                          List of functionsResult data type |   Schema   |       Name       | Argument
datatypes 
------------------+------------+------------------+---------------------numeric          | pg_catalog | numeric
| bigintnumeric          | pg_catalog | numeric          | double precisionnumeric          | pg_catalog | numeric
   | integernumeric          | pg_catalog | numeric          | numeric, integernumeric          | pg_catalog | numeric
       | realnumeric          | pg_catalog | numeric          | smallintnumeric          | pg_catalog | numeric
| text 
etc...

So you want ...(data2::text)::numeric

That's not to say I think it's a good idea to store all your values in text
fields - you're throwing away all the type checking PG can do for you.
--  Richard Huxton


Re: Type coercion on column in a query

From
Ian Barwick
Date:
On Thursday 08 May 2003 02:59, Kenny Mok wrote:
> Dear all,
>
> I am just a novice in SQL and also in PostgreSQL. I have encountered some
> difficulties in developing a website using PostgreSQL as my backend
> database.
>
> My situation is, I have such a table "test" :
>
> testing=# SELECT * from test ;
>  id  |  data1      | data2
> ----+------------+--------
>   1  | 2003-5-6 | 3 days
>   2  | 1234       | 34
> (2 rows)
>
> where columns data1 and data 2 are with data types varchar, where all my
> data is stored into it.
>
> What I want to do is to extracts the data from this database and casting it
> before shown in front of my client. So, I do the following queries :
>
> testing=# SELECT
> testing-#    cast(data1 as numeric) - cast(data2 as numeric)
> testing-#    as result from test
> testing-#    where id = 2;
> ERROR:  Cannot cast type 'character varying' to 'numeric'

There is no cast between varchar and numeric / int; you will need to
go via text, e.g.
 SELECT data1::text::numeric

or
 SELECT cast(cast(data1 as text) as numeric)



Ian Barwick
barwick@gmx.net




Re: Type coercion on column in a query

From
Randall Lucas
Date:
Along the same lines, is it possible to tell whether a column may be  
cast to a given type (e.g. numeric) without throwing an error?

Specifically, I have some values that will probably be numbers but  
might have some free text or other gobbledygook in there.  I want to  
take the sum of all the numeric values, and maybe the average as well.   
So what I envision is:

table dirty_data (     id                 int,     dirty_numbers         text
);

function safe_numeric_cast(text) returns numeric as '
beginif $1::numeric::text = $1 then         return $1::numeric;     else         return null;     end if;
end;
' language 'pseudopgsql';

select sum( safe_numeric_cast(dirty_numbers) ) from dirty_data where  
safe_numeric_cast(dirty_numbers) is not null;

However, the holdup seems to be that I can't even try to cast a dirty  
string to numeric lest I throw an "ERROR:  Bad numeric input format."   
Suggestions?

Best,

Randall


On Wednesday, May 14, 2003, at 11:28 AM, Richard Huxton wrote:

> On Thursday 08 May 2003 1:59 am, Kenny Mok wrote:
>> Dear all,
>>
>> I am just a novice in SQL and also in PostgreSQL. I have encountered  
>> some
>> difficulties in developing a website using PostgreSQL as my backend
>> database.
>>
>> My situation is, I have such a table "test" :
>>
>> testing=# SELECT * from test ;
>>  id  |  data1      | data2
>> ----+------------+--------
>>   1  | 2003-5-6 | 3 days
>>   2  | 1234       | 34
>> (2 rows)
>>
>> where columns data1 and data 2 are with data types varchar, where all  
>> my
>> data is stored into it.
>>
>> What I want to do is to extracts the data from this database and  
>> casting it
>> before shown in front of my client. So, I do the following queries :
>
> You can see what functions are available and what types they support  
> with \df
> from the psql command-line.
>
> => \df numer*
>                            List of functions
>  Result data type |   Schema   |       Name       | Argument data types
> ------------------+------------+------------------ 
> +---------------------
>  numeric          | pg_catalog | numeric          | bigint
>  numeric          | pg_catalog | numeric          | double precision
>  numeric          | pg_catalog | numeric          | integer
>  numeric          | pg_catalog | numeric          | numeric, integer
>  numeric          | pg_catalog | numeric          | real
>  numeric          | pg_catalog | numeric          | smallint
>  numeric          | pg_catalog | numeric          | text
> etc...
>
> So you want ...(data2::text)::numeric
>
> That's not to say I think it's a good idea to store all your values in  
> text
> fields - you're throwing away all the type checking PG can do for you.
> -- 
>   Richard Huxton
>
> ---------------------------(end of  
> broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/docs/faqs/FAQ.html
>



Re: Type coercion on column in a query

From
Richard Huxton
Date:
On Wednesday 14 May 2003 5:10 pm, Randall Lucas wrote:
> Along the same lines, is it possible to tell whether a column may be
> cast to a given type (e.g. numeric) without throwing an error?
>
> Specifically, I have some values that will probably be numbers but
> might have some free text or other gobbledygook in there.  I want to
> take the sum of all the numeric values, and maybe the average as well.
> So what I envision is:
>
> table dirty_data (
>       id                 int,
>       dirty_numbers         text
> );

> select sum( safe_numeric_cast(dirty_numbers) ) from dirty_data where
> safe_numeric_cast(dirty_numbers) is not null;

You'd have to write "safe_numeric_cast()" in plperl, or possibly pltcl (sorry,
I don't use TCL). There's no exception handling in Postgresql (nor will there
be in the next few months).

Alternatively, you could conceivably write a bunch of is_numeric(), is_int()
etc functions and test first.

--  Richard Huxton


Re: Type coercion on column in a query

From
Randall Lucas
Date:
Thanks Richard,

Do you know if there's a way to access the same method that Postgres 
uses for determining cast-ability?

I don't mind writing a new function in plperl.  I am concerned not so 
much about the difficulty of the numeric type, but as I move into other 
types, such as timestamp, I don't want to re-implement half-assedly the 
heuristics for date determination when those are already pretty 
bulletproof in Postgres.

Best,

Randall


On Wednesday, May 14, 2003, at 12:32 PM, Richard Huxton wrote:

> On Wednesday 14 May 2003 5:10 pm, Randall Lucas wrote:
>> Along the same lines, is it possible to tell whether a column may be
>> cast to a given type (e.g. numeric) without throwing an error?
>>
>> Specifically, I have some values that will probably be numbers but
>> might have some free text or other gobbledygook in there.  I want to
>> take the sum of all the numeric values, and maybe the average as well.
>> So what I envision is:
>>
>> table dirty_data (
>>       id                 int,
>>       dirty_numbers         text
>> );
>
>> select sum( safe_numeric_cast(dirty_numbers) ) from dirty_data where
>> safe_numeric_cast(dirty_numbers) is not null;
>
> You'd have to write "safe_numeric_cast()" in plperl, or possibly pltcl 
> (sorry,
> I don't use TCL). There's no exception handling in Postgresql (nor 
> will there
> be in the next few months).
>
> Alternatively, you could conceivably write a bunch of is_numeric(), 
> is_int()
> etc functions and test first.
>
> -- 
>   Richard Huxton
>



Re: Type coercion on column in a query

From
Richard Huxton
Date:
On Wednesday 14 May 2003 5:46 pm, Randall Lucas wrote:
> Thanks Richard,
>
> Do you know if there's a way to access the same method that Postgres
> uses for determining cast-ability?

I don't *think* so (bear in mind I'm not a developer, just a user). My
understanding is that PG does the following:
1. Identify types involved
2. Look up the function required to convert
3. Execute the function

It's the function itself that raises an error in the case of say
text=>timestamp where the text contains garbage. I don't think there's much
the developers can do about this - if you want to be able to add new types
simply, they need to be fairly self contained.

Now it shouldn't be beyond the wit of man to be able to produce an
is_castable(value, destination_type) function that calls these conversion
functions and traps the error.  In this particular case there shouldn't* be
any side effects to worry about. However, that's probably more work than
you're interested in.

> I don't mind writing a new function in plperl.  I am concerned not so
> much about the difficulty of the numeric type, but as I move into other
> types, such as timestamp, I don't want to re-implement half-assedly the
> heuristics for date determination when those are already pretty
> bulletproof in Postgres.

I think you're out of luck here. The "proper" way to do this is:
1. try to insert values into columns of correct type
2. when it fails, handle error in application

* - that's shouldn't as in I can't think of a good reason why right now
--  Richard Huxton