postgresql function returns multiple columns - postgresql

I am confused about the passing process of the parameter from functions created in Postgres:
create type IncorrectRecord as (pattern_number integer, uoc_number integer);
create or replace function text1(pattern text, uoc_threshold integer)
returns setof IncorrectRecord
as $$
begin
return next count(v1.code) as pattern_number, count(v2.code) as uoc_number
from (select * from q1_1 where code like pattern) as v1, (select
* from q1_1 where code like pattern and uoc > uoc_threshold) as v2;
return;
end
$$ language plpgsql;
I have modified some, there is no parameters errors but it still does not work.
when I tested it with
select *
from test1('ECO%', 8)
error: function returns two columns.
Is there any thing wrong with the type? How can I fix it?.

As the message says you are returning two columns. Return a composite type instead:
return next (
count(v1.code) as pattern_number, count(v2.code) as uoc_number
)::IncorrectRecord

Related

problem creating PLpgSQL function which accepts ARRAY as INPUT and returns SETOF RECORD from the table

I'm trying to create function which will accept ARRAY as INPUT and then return SETOF RECORD for each of the parameter in ARRAY.
I have table country_regions which consists of 3 Columns: id int, region_name TEXT, country_name TEXT;
My Functions code looks like this:
CREATE OR REPLACE FUNCTION search1(TEXT[])
RETURNS SETOF RECORD AS $$
DECLARE x RECORD;
BEGIN
FOR x IN
SELECT *
FROM company_regions
WHERE country_name = $1::TEXT
LOOP
RETURN NEXT x;
END LOOP;
END; $$
LANGUAGE plpgSQL;
This Function was created successfully, but when I try to call the function like this:
SELECT * FROM search1(ARRAY ['usa', 'canada']) AS search1(id int, region_name TEXT, country_name text)
it returns table with 0 rows in it.
Can someone tell me what am I doing wrong? I'm completely new to SQL, tried to find answer in other post but I still could not figure out the problem.
You try to compare text value versus text[].
CREATE OR REPLACE FUNCTION search1(text[])
RETURNS SETOF company_regions AS $$
BEGIN
RETURN QUERY SELECT * FROM company_regions
WHERE country_name = ANY($1);
END
$$ LANGUAGE plpgsql STABLE
Attention - functions like this are black box for optimizer. Usually is not too good (from performance perspective) using functions like envelops of one SQL statement. In complex query it can block some optimizations (Mainly if you forget to set correct flag of function - in this case STABLE).

Postgres: ERROR: value too long for type character(4)

I'm new to Postgres and currently trying to write a function that takes in an integer and then calls another (definitely working) pre-written function with that input. If I call the pre-written function directly, e.g.:
select * from func(3456789);
I get the result I expect, with no errors. However, if I call it inside my function:
create or replace function my_func(_id integer)
returns setof Record
as $$
declare
rec Record;
begin
for rec in
select * from func(_id)
loop
return next rec;
end loop;
end;
$$ language plpgsql
;
where I call it with exactly the same parameter:
select * from my_func(3456789);
I get the following error:
ERROR: value too long for type character(4)
CONTEXT: PL/pgSQL function my_func(integer) line 5 at FOR over SELECT rows
Why are these two cases different, and how can I fix it?
EDIT:
func(_sid) returns this:
CREATE FUNCTION func(_sid integer) RETURNS SETOF Record
LANGUAGE plpgsql
AS $$ ...
and Record is defines like this:
create type Record as (code char(8), name char(4), num integer, work char(4));
Every line that is returned by your function func is mapped to a Record.
So the error you are getting says that one of the lines in the function result contains at column positions of name and/or work a value bigger than the one required by the columns (wich is 4).

Function returns only one column when return type is record type postgres

I have a function that has the return type of record.
Below is the function am using, basically what the function does is , it takes in input paramter and queries the database to return the columns:
drop function if exists test_proc(sr_number1 bigint);
create or replace function test_proc(sr_number1 bigint) RETURNS record /*SETOF tbl*/ AS $$
declare
i integer default 0;
record_type record;
begin
select sr_num,product_number,phone,addr into record_type from my_table where sr_num=sr_number1;
return record_type;
end
$$ LANGUAGE plpgsql;
Unfortunately, when I execute the function as
select test_proc(12345); I get the result as a comma separated list in just one column like (sr_num,product_number,phone,addr). But what I was hoping to have it return was a table row with the column values and their respective column names.
I also tried executing the function as
select * from test_proc(12345); but get the following error
ERROR: a column definition list is required for functions returning "record"
When querying a function that returns a record you must specify the type of record you want to get in the result
select * from test_proc(12345) f(b bigint, t text);
This should work.
A better solution is to declare the type of record in the function
CREATE OR REPLACE FUNCTION test_proc(sr_number1 bigint)
RETURNS TABLE(b bigint, t text) AS $$ $$

How to return multiple rows from PL/pgSQL function?

I have spent good amount of time trying to figure it out and I haven't been able to resolve it. So, I need your help please.
I am trying to write a PL/pgSQL function that returns multiple rows. The function I wrote is shown below. But it is not working.
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS SETOF RECORD
AS
$$
DECLARE result_record keyMetrics;
BEGIN
return QUERY SELECT department_id into result_record.visits
from fact_department_daily
where report_date='2013-06-07';
--return result_record;
END
$$ LANGUAGE plpgsql;
SELECT * FROM get_object_fields;
It is returning this error:
ERROR: RETURN cannot have a parameter in function returning set;
use RETURN NEXT at or near "QUERY"
After fixing the bugs #Pavel pointed out, also define your return type properly, or you have to provide a column definition list with every call.
This call:
SELECT * FROM get_object_fields()
... assumes that Postgres knows how to expand *. Since you are returning anonymous records, you get an exception:
ERROR: a column definition list is required for functions returning "record"
One way (of several) to fix this is with RETURNS TABLE (Postgres 8.4+):
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS TABLE (department_id int) AS
$func$
BEGIN
RETURN QUERY
SELECT department_id
FROM fact_department_daily
WHERE report_date = '2013-06-07';
END
$func$ LANGUAGE plpgsql;
Works for SQL functions just the same.
Related:
PostgreSQL: ERROR: 42601: a column definition list is required for functions returning "record"
I see more bugs:
first, a SET RETURNING FUNCTIONS call has following syntax
SELECT * FROM get_object_fields()
second - RETURN QUERY forwards query result to output directly. You cannot store this result to variable - it is not possible ever in PostgreSQL now.
BEGIN
RETURN QUERY SELECT ....; -- result is forwarded to output directly
RETURN; -- there will not be any next result, finish execution
END;
third - these simple functions is better to implement in SQL languages
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS SETOF RECORD AS $$
SELECT department_id WHERE ...
$$ LANGUAGE sql STABLE;
Here's one way
drop function if exists get_test_type();
drop type if exists test_comp;
drop type if exists test_type;
drop type if exists test_person;
create type test_type as (
foo int,
bar int
);
create type test_person as (
first_name text,
last_name text
);
create type test_comp as
(
prop_a test_type[],
prop_b test_person[]
);
create or replace function get_test_type()
returns test_comp
as $$
declare
a test_type[];
b test_person[];
x test_comp;
begin
a := array(
select row (m.message_id, m.message_id)
from message m
);
-- alternative 'strongly typed'
b := array[
row('Bob', 'Jones')::test_person,
row('Mike', 'Reid')::test_person
]::test_person[];
-- alternative 'loosely typed'
b := array[
row('Bob', 'Jones'),
row('Mike', 'Reid')
];
-- using a select
b := array (
select row ('Jake', 'Scott')
union all
select row ('Suraksha', 'Setty')
);
x := row(a, b);
return x;
end;
$$
language 'plpgsql' stable;
select * from get_test_type();
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS table (department_id integer)
AS
$$
DECLARE result_record keyMetrics;
BEGIN
return QUERY
SELECT department_id
from fact_department_daily
where report_date='2013-06-07';
--return result_record;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM get_object_fields()

Declaring the tuple structure of a record in PL/pgSQL

I can't find anything in the PostgreSQL documentation that shows how to declare a record, or row, while declaring the tuple structure at the same time. If you don't define you tuple structure you get the error "The tuple structure of a not-yet-assigned record is indeterminate".
This is what I'm doing now, which works fine, but there must be a better way to do it.
CREATE OR REPLACE FUNCTION my_func()
RETURNS TABLE (
"a" integer,
"b" varchar
) AS $$
DECLARE r record;
BEGIN
CREATE TEMP TABLE tmp_t (
"a" integer,
"b" varchar
);
-- Define the tuple structure of r by SELECTing an empty row into it.
-- Is there a more straight-forward way of doing this?
SELECT * INTO r
FROM tmp_t;
-- Now I can assign values to the record.
r.a := at.something FROM "another_table" at
WHERE at.some_id = 1;
-- A related question is - how do I return the single record 'r' from
-- this function?
-- This works:
RETURN QUERY
SELECT * FROM tmp_t;
-- But this doesn't:
RETURN r;
-- ERROR: RETURN cannot have a parameter in function returning set
END; $$ LANGUAGE plpgsql;
You are mixing the syntax for returning SETOF values with syntax for returning a single row or value.
-- A related question is - how do I return the single record 'r' from
When you declare a function with RETURNS TABLE, you have to use RETURN NEXT in the body to return a row (or scalar value). And if you want to use a record variable with that it has to match the return type. Refer to the code examples further down.
Return a single value or row
If you just want to return a single row, there is no need for a record of undefined type. #Kevin already demonstrated two ways. I'll add a simplified version with OUT parameters:
CREATE OR REPLACE FUNCTION my_func(OUT a integer, OUT b text)
AS
$func$
BEGIN
a := ...;
b := ...;
END
$func$ LANGUAGE plpgsql;
You don't even need to add RETURN; in the function body, the value of the declared OUT parameters will be returned automatically at the end of the function - NULL for any parameter that has not been assigned.
And you don't need to declare RETURNS RECORD because that's already clear from the OUT parameters.
Return a set of rows
If you actually want to return multiple rows (including the possibility for 0 or 1 row), you can define the return type as RETURNS ...
SETOF some_type, where some_type can be any registered scalar or composite type.
TABLE (col1 type1, col2 type2) - an ad-hoc row type definition.
SETOF record plus OUT parameters to define column names andtypes.
100% equivalent to RETURNS TABLE.
SETOF record without further definition. But then the returned rows are undefined and you need to include a column definition list with every call (see example).
The manual about the record type:
Record variables are similar to row-type variables, but they have no
predefined structure. They take on the actual row structure of the
row they are assigned during a SELECT or FOR command.
There is more, read the manual.
You can use a record variable without assigning a defined type, you can even return such undefined records:
CREATE OR REPLACE FUNCTION my_func()
RETURNS SETOF record AS
$func$
DECLARE
r record;
BEGIN
r := (1::int, 'foo'::text); RETURN NEXT r; -- works with undefined record
r := (2::int, 'bar'::text); RETURN NEXT r;
END
$func$ LANGUAGE plpgsql;
Call:
SELECT * FROM my_func() AS x(a int, b text);
But this is very unwieldy as you have to provide the column definition list with every call. It can generally be replaced with something more elegant:
If you know the type at time of function creation, declare it right away (RETURNS TABLE or friends).
CREATE OR REPLACE FUNCTION my_func()
RETURNS SETOF tbl_or_type AS
$func$
DECLARE
r tbl_or_type;
BEGIN
SELECT INTO tbl_or_type * FROM tbl WHERE id = 10;
RETURN NEXT r; -- type matches
SELECT INTO tbl_or_type * FROM tbl WHERE id = 12;
RETURN NEXT r;
-- Or simpler:
RETURN QUERY
SELECT * FROM tbl WHERE id = 14;
END
$func$ LANGUAGE plpgsql;
If you know the type at time of the function call, there are more elegant ways using polymorphic types:
Refactor a PL/pgSQL function to return the output of various SELECT queries
Your question is unclear as to what you need exactly.
There might be some way that avoids the explicit type declaration, but offhand the best I can come up with is:
CREATE TYPE my_func_return AS (
a integer,
b varchar
);
CREATE OR REPLACE FUNCTION my_func()
RETURNS my_func_return AS $$
DECLARE
r my_func_return;
BEGIN
SELECT 1, 'one' INTO r.a, r.b;
RETURN r;
END; $$ LANGUAGE plpgsql;
Oh, I almost forgot the simplest way to do this:
CREATE OR REPLACE FUNCTION my_func2(out a int, out b text)
RETURNS RECORD AS $$
BEGIN
SELECT 1, 'one' INTO a, b;
RETURN;
END; $$ LANGUAGE plpgsql;
It is much easier to use OUT parameters rather than a record. If iteratively building a set of records (a table) use RETURN NEXT. If generating from a query, use RETURN QUERY. See:
https://stackoverflow.com/a/955289/398670
and:
http://www.postgresql.org/docs/current/static/plpgsql-declarations.html
http://www.postgresql.org/docs/current/static/sql-createfunction.html
http://www.postgresonline.com/journal/archives/129-Use-of-OUT-and-INOUT-Parameters.html
Think:
CREATE OR REPLACE FUNCTION my_func(OUT a integer, OUT b varchar) RETURNS SETOF RECORD AS $$
BEGIN
-- Assign a and b, RETURN NEXT, repeat. when done, RETURN.
END;
$$ LANGUAGE 'plpgsql';