1

I am trying to create a function in Postgres as follows:

Create function Samplefunc() 
returns resultdata( Tested int, Score int,
       Growth int) as
$BODY$
Select 
       Count(distinct student_id) Tested, 
       Cast(Avg(R.raw_score) as Int)  Score,
       Avg(R.growth) as Growth
from results R
where R.id=1 and test_id='ME04';
$BODY$
LANGUAGE sql;

But I am getting the following error:

ERROR:  syntax error at or near "int"
LINE 2: returns resultdata( NTested int, RawScore int,
                                    ^

********** Error **********

ERROR: syntax error at or near "int"
SQL state: 42601
Character: 59

Where am I going wrong?

4 Answers 4

3
CREATE FUNCTION samplefunc() 
  RETURNS TABLE(ntested int, rawscore int, growth int) AS
$func$
SELECT count(DISTINCT r.student_id) -- AS NTested
      ,avg(r.raw_score)::int        -- AS RawScore
      ,avg(r.growth)::int           -- AS Growth
FROM   reports_results r
WHERE  r.test_type_id = 1
AND    r.test_id = '201403MAME04'
$func$ LANGUAGE sql;
  • The clause to return a table is RETURNS TABLE.

  • Carefully avoid conflicts between OUT parameters and column names. (I had such a conflict in my first draft). Table-qualify columns to disambiguate. All field names in RETURNS TABLE are effectively OUT parameters and visible inside the function (almost) everywhere.

Also:

If the query is guaranteed to return a single row, you might want to combine OUT parameters with RETURNS record:

CREATE FUNCTION samplefunc(OUT ntested int, OUT rawscore int, OUT growth int) 
  RETURNS record  AS ...

The subtle difference: This way you get a single row with NULL values if nothing is found, where the first form would return nothing / no row.

Add IN parameters (request in comment)

CREATE FUNCTION samplefunc(_test_type_id int, _test_id text) 
  RETURNS TABLE(ntested int, rawscore int, growth int) AS
$func$
SELECT count(DISTINCT r.student_id)
      ,avg(r.raw_score)::int
      ,avg(r.growth)::int
FROM   reports_results r
WHERE  r.test_type_id = $1   -- or: = _test_type_id in Postgres 9.2+
AND    r.test_id = $2        -- or: = _test_id
$func$ LANGUAGE sql;

Many related answers here on SO with more code examples. Like:

Try a search.

Sign up to request clarification or add additional context in comments.

2 Comments

hi..thanks for the answer. it worked great! how do i modify it to pass some arguments such that i dont have to define it like "where R.test_type_id=1 and test_id='201403MAME04';" anymore?
@crozzfire: I added another answer to my answer.
1

Try not specifying the details of the composite return type. However, I think the return structure must exist first.

Create table resultdata (NTested int, RawScore int, Growth int);

Create function Samplefunc() returns resultdata as
$BODY$
Select 
   Count(distinct student_id) as NTested, 
   Cast(Avg(R.raw_score) as Int) as RawScore,
   Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

Or try explicitly returning a table:

Create function Samplefunc() 
    returns Table (NTested int, RawScore int, Growth int) as
$BODY$
Select 
   Count(distinct student_id) as NTested, 
   Cast(Avg(R.raw_score) as Int) as RawScore,
   Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

I think you can also return a set of records using output parameters:

Create function Samplefunc(OUT NTested int, OUT RawScore int, OUT Growth int) 
    returns SetOf Record as
$BODY$
Select 
   Count(distinct student_id) as NTested, 
   Cast(Avg(R.raw_score) as Int) as RawScore,
   Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

Comments

1

You are trying to return a record containing multiple output parameters. You should do like:

Create function Samplefunc(out NTested int, out RawScore int, out Growth int) as
$BODY$
Select 
       Count(distinct student_id) NTested, 
       Cast(Avg(R.raw_score) as Int)  RawScore,
       Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

You can do the same thing more verbosely with an explicitly named composite type; like

CREATE TYPE resultdata AS (NTested int, RawScore int, Growth int);

CREATE FUNCTION Samplefunc() RETURNS resultdata
    AS .......

Or using a TABLE function like

CREATE FUNCTION Samplefunc() RETURNS TABLE(NTested int, RawScore int, Growth int)
AS
......

See PostgreSQL Documentation for more information on the same

Comments

0

If you have not defined a type "resultset" as Luke rightly assumed, then try returning a table instead.

Create function Samplefunc() 
returns table( NTested int, RawScore int,
       Growth int) as
$BODY$
Select 
       Count(distinct student_id) NTested, 
       Cast(Avg(R.raw_score) as Int)  RawScore,
       Avg(R.growth) as Growth
from reports_results R
where R.test_type_id=1 and test_id='201403MAME04';
$BODY$
LANGUAGE sql;

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.