How to return a value from a function if no value is found

梦想与她 提交于 2019-12-01 07:09:15

问题


I'm attempting to return 0.0 if the following function does not return anything:

CREATE OR REPLACE FUNCTION get_height(firstn VARCHAR, lastn VARCHAR)
  RETURNS FLOAT AS
$$
DECLARE
    height FLOAT = 0.0;
BEGIN
    SELECT into height AVG(((p.h_feet * 12) + p.h_inches) * 2.54)
    FROM player p
    WHERE p.firstname = firstn AND p.lastname = lastn; 

    RETURN height;
END;
$$ LANGUAGE plpgsql;

I've tried searching for it and found that COALESCE does not work. Does anyone have any ideas how to solve this?

Table structure:

 create table player(
                     firstname text
                    ,lastname text
                    ,h_feet INT
                    ,h_inches INT
                    );

Example data:

  insert into player values ('Jimmy','Howard',6,2);

回答1:


Here is the script I used. As you can see I run PostgreSQL 9.4.1. I used HeidiSQL to launch the queries. Are you sure that you correctly updated your function? I just noted that you used a different function ('player_height') in a comment instead of 'get_height' in you original post.

select version();
-- PostgreSQL 9.4.1, compiled by Visual C++ build 1800, 64-bit

delimiter //

CREATE OR REPLACE FUNCTION get_height(firstn VARCHAR, lastn VARCHAR)         
RETURNS FLOAT AS $$
DECLARE
height FLOAT = 0.0;
BEGIN
    SELECT into height AVG(((p.h_feet * 12) + p.h_inches) * 2.54)
    FROM players p
    WHERE p.firstname = firstn AND p.lastname = lastn; 
        return coalesce(height, 0.0);
END;
$$ LANGUAGE plpgsql;

delimiter;

CREATE TABLE players (
     firstname varchar(40),
     lastname  varchar(40),
     h_feet int,
     h_inches int);


insert into players values ('Jimmy', 'Howard', 6, 2);

select * from get_height('Jimmy', 'Howard');
-- gives 187.96

select * from get_height('Random', 'Guy');
-- gives 0



回答2:


Explanation

The root of the problem is the fuzzy definition of "not anything".

if the following function does not return anything

NULL is not nothing, it's just unknown what it is exactly. "Nothing" in terms of SQL would be no row: nothing is returned at all. That typically happens when no row is found. But when using aggregate functions, that cannot happen because, per documentation:

... these functions return a null value when no rows are selected.

avg() returns NULL when no rows are found (so not "nothing"). You get a row with a NULL value as result - which overwrites your init value in the code you demonstrate.

Solution

Wrap the result in COALESCE. Demonstrating a much simpler SQL function:

CREATE OR REPLACE FUNCTION get_height_sql(firstn varchar, lastn varchar)
  RETURNS float AS
$func$
   SELECT COALESCE(AVG(((p.h_feet * 12) + p.h_inches) * 2.54)::float, 0)
   FROM   player p
   WHERE  p.firstname = firstn
   AND    p.lastname = lastn
$func$  LANGUAGE sql STABLE;

SQL Fiddle.

The same can be used in a plpgsql function. This function can be STABLE, might help with performance in the context of bigger queries.

Other cases

If you actually can get no row from a query, a simple COALESCE would fail, because it's never executed.

For a single value result you can just wrap the whole query like:

SELECT COALESCE((SELECT some_float FROM ... WHERE ... LIMIT 1), 0) AS result
  • How to display a default value when no match found in a query?

PL/pgSQL has the ability to check before actually returning from the function. This works for multiple rows with one or more columns, too. There is an example in the manual demonstrating the use of FOUND:

...
RETURN QUERY SELECT foo, bar ...;

IF NOT FOUND THEN
    RETURN QUERY VALUES ('foo_default'::text, 'bar_default'::text);
END IF;
...

Related:

  • Return setof record (virtual table) from function
  • PostgreSQL - Check foreign key exists when doing a SELECT

To always return exactly one row, you can also use pure SQL:

SELECT foo, bar FROM tbl
UNION ALL
SELECT 'foo_default', 'bar_default'
LIMIT 1;

If the first SELECT returns no row, the second SELECT returns a row with defaults.




回答3:


return coalesce(height, 0::decimal(10,2)); should do the trick




回答4:


try not found condition

SELECT ... into ...
FROM ...
WHERE ...; 

if not found then
  RETURN 0;
end if;


来源:https://stackoverflow.com/questions/29293018/how-to-return-a-value-from-a-function-if-no-value-is-found

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!