user373201
user373201

Reputation: 11455

postgres check if null then cast to numeric

I am trying check if a value is null if so the select null else cast to numeric, but it throws an error. This is actually part of an insert statement

INSERT into someTable(name,created,power) 
SELECT 'xyz',now(),
case when :power ='null' then NULL else cast(:power as numeric) end from abc 

error that I get is

Error: ERROR: invalid input syntax for type numeric: "null"

:power is a variable that can be given any value using java code. If I give a value of null it give an error.

In code I get the following error from the java stack trace

org.postgresql.util.PSQLException: ERROR: cannot cast type bytea to numeric

Upvotes: 4

Views: 43170

Answers (5)

Erwin Brandstetter
Erwin Brandstetter

Reputation: 658907

Error

SELECT CASE WHEN 'null' = 'null' THEN NULL ELSE cast('null' AS numeric) END 

No error

DO
$$
DECLARE
   power text := 'null';
BEGIN
   PERFORM CASE WHEN power = 'null' THEN null ELSE cast(power AS numeric) END;
END
$$

Explanation

If you build a query string, the expression cast('null' AS numeric) or simply 'null'::numeric always raises an exception, even in an ELSE block that is never executed, because it is invalid input syntax and the exception is raised during the syntax check (like the error message implies), not during execution.

A CASE statement like you display only makes sense with a parameter or variable not with literals. The second instance of the literal has no connection to the first instance whatsoever after the query string has been assembled.

For dynamic SQL like that, you need to check the value before you build the query string. Or you use a function or prepared statement and pass the value as parameter. That would work, too.

More advice after comment:

In your particular case you could check the value in the app and build a query string like this:

INSERT INTO tbl(name, abc_id, created, power) 
SELECT 'xyz'
     , abc_id
     , now()
     , <insert_value_of_power_or_NULL_here> -- automatically converted to numeric
FROM   abc;

You may be interested in a different approach to INSERT data from a file conditionally.
Use COPY for files local to the server or psql's meta-command \copy for files local to the client.

Upvotes: 11

MrCris
MrCris

Reputation: 71

I was trying to do something similar in order to update/insert some records where a numeric value can be null or not. You can validate a variable before you send it to the function or inside the function depending the value passed (For me using a variable is better than use CASE WHEN THEN ELSE END CASE every time you need to validate the value)

So to work with the NULL values using a regular comparison operand in order to find a record to update can be done by turning transform_null_equals to ON

I hope this help someone

CREATE OR REPLACE FUNCTION update_insert_transaction(vcodaccount integer, vcodaccountaux text, 
  vdescription text, vcodgroup integer)
  RETURNS integer AS $$
DECLARE
  n integer = 0;
  vsql text = 'NULL'; 
BEGIN 
    IF vcodaccountaux <> '' THEN
        vsql = vcodaccountaux;
    END IF; 
        SET LOCAL transform_null_equals TO ON;
        EXECUTE 'UPDATE account_import_conf SET (codaccount, codaccountaux, description, codgroup) = 
            ('||vcodaccount||','||vsql||',trim('||quote_literal(vdescription)||'),'||vcodgroup||') 
            WHERE codaccount='||vcodaccount||' AND codaccountaux = '||vsql||' RETURNING * ';
    GET DIAGNOSTICS n = ROW_COUNT;
    IF n = 0 THEN
    EXECUTE 'INSERT INTO account_import_conf (codaccount, codaccountaux, description, codgroup)         
        SELECT '||vcodaccount||','||vsql||' ,trim('||quote_literal(vdescription)||'),'||vcodgroup||';';
    END IF;
RETURN n;
END;$$
  LANGUAGE plpgsql;

Upvotes: 0

ramigg
ramigg

Reputation: 1305

if the field value is null, and you want in this case to map it to some value you can use coalesce(field_name, 'Some value') or coalesce(field_name, 123).
For full documentation see here.

Upvotes: 9

maniek
maniek

Reputation: 7307

INSERT into someTable(name,created,power) SELECT 'xyz',now(),
   case :power when 'null' then NULL else :power end::numeric from abc

Upvotes: 0

aleroot
aleroot

Reputation: 72676

You have to check with the IS operator, and not with the equal when you dealing with NULL :

INSERT into someTable(name,created,power) 
SELECT 'xyz',now(),
case when :power IS null then NULL else cast(:power as numeric) end from abc 

Upvotes: 1

Related Questions