I want to return four conditional aggregates from a function. I tried using CASE
expressions. My SQL:
CREATE OR REPLACE FUNCTION get_grade(IN integer, out integer,out integer,out integer,out integer) AS
$BODY$
begin
select
sum(case when t.pirority = 66 then 1 else 0 end) as I ,
sum(case when t.pirority = 67 then 1 else 0 end) as II,
sum(case when t.pirority = 68 then 1 else 0 end) as III,
sum(case when t.pirority = 225 then 1 else 0 end) as IIII
from dt_info t
where t.registrant = $1
end
$BODY$
LANGUAGE 'plpgsql' VOLATILE
When I use:
select * from get_grade(22);
it doesn't work as expected.
Also tried:
CREATE OR REPLACE FUNCTION get_grade(IN integer) returns setof record AS
$BODY$
select
sum(case when t.pirority = 66 then 1 else 0 end) as I,
sum(case when t.pirority = 67 then 1 else 0 end) as II,
sum(case when t.pirority = 68 then 1 else 0 end) as III,
sum(case when t.pirority = 225 then 1 else 0 end) as IIII
from dt_info t
where t.registrant = $1
$BODY$
LANGUAGE 'sql' VOLATILE;
Then I execute:
select * from get_grade(25) as (v1 integer, v2 integer, v3 integer, v4 integer)
Error:
ERROR: function return row and query-specified return row do not match
How to get this right?
Try this:
You can write a simple query like this with
LANGUAGE plpgsql
. You can also just useLANGUAGE sql
. Either has pros and cons. Showing an SQL function. Don't quote the language name. The manual:Column aliases inside the function body are not visible outside. They only serve as documentation in this case. Use named
OUT
parameters or they get default names.RETURNS TABLE
makes it a set-returning function and requires columns names in any case.OUT
parameters are visible inside every DML SQL statement inside the function body. Table-qualify column names that would otherwise conflict withOUT
parameter names. Don't use aliases that would conflict. I commented out your aliases to be clear (though modern versions of Postgres wouldn't conflict there).Data types of returned columns have to match the declaration in the header exactly.
sum()
orcount()
returnbigint
. You have to cast tointeger
explicitly to match the return type.Unquoted upper case identifiers are folded to lower case in Postgres anyway, and only serve to confuse.
I used shorter (and a bit faster) expressions for your conditional count. In Postgres 9.4 or later use an aggregate
FILTER
instead. See: