Stored functions postgresql returning table - sql

A novice when it comes to stored procedures/functions. I have searched Google, Stackoverflow, and Youtube and are finding all sorts of examples that are convoluted, some not in English.
I'm trying to understand the basic syntax for a stored function to return a table in Postgresql. In MySql this is elementary but I can't seem to wrap my head around the syntax for Postgresql I have the SQL statement I need to return the rows I want (table), as seen below. I have tried the following code but it doesn't work. Help is much appreciated, thanks in advance.
CREATE OR REPLACE FUNCTION Getcurrent()
RETURNS table AS $schedule$
$BODY$ BEGIN
SELECT *
FROM archived_table
WHERE table_id>=ALL(SELECT table_id FROM archived_table);
RETURN schedule;
END;$BODY$
LANGUAGE plpgsql;
********** Error **********
ERROR: syntax error at or near "AS"
LINE 2: RETURNS table AS $schedule$
^
This is the error message.
I have referenced the following link and have had no luck with this.https://www.postgresql.org/docs/9.1/static/sql-createfunction.html
Im using pgAdminIII, in the public schema, on my company's server.
The desired results is to have the table returned once the function is called.

RETURNS TABLE is not complete, hence the error message.
You can use the RETURNS SETOF <table_name> form, if you intend to return all columns of a table.
Otherwise, you'll need to mention every output column by name and type, with either RETURNS TABLE:
RETURNS TABLE (
col_alias_1 INT,
col_alias_2 TEXT,
col_alias_3 <some_other_type>,
...
)
Or with OUT parameters + RETURNS SETOF RECORD to indicate that you'll (possibly) return multiple rows at once.
Also, if your operation is as simple as a few SQL statements, use LANGUAGE SQL instead:
CREATE OR REPLACE FUNCTION Getcurrent()
RETURNS SETOF archived_table
LANGUAGE SQL
AS $BODY$
SELECT *
FROM archived_table
WHERE table_id>=ALL(SELECT table_id FROM archived_table);
$BODY$;

Related

Input table for PL/pgSQL function

I would like to use a plpgsql function with a table and several columns as input parameter. The idea is to split the table in chunks and do something with each part.
I tried the following function:
CREATE OR REPLACE FUNCTION my_func(Integer)
RETURNS SETOF my_part
AS $$
DECLARE
out my_part;
BEGIN
FOR i IN 0..$1 LOOP
FOR out IN
SELECT * FROM my_func2(SELECT * FROM table1 WHERE id = i)
LOOP
RETURN NEXT out;
END LOOP;
END LOOP;
RETURN;
END;
$$
LANGUAGE plpgsql;
my_func2() is the function that does some work on each smaller part.
CREATE or REPLACE FUNCTION my_func2(table1)
RETURNS SETOF my_part2 AS
$$
BEGIN
RETURN QUERY
SELECT * FROM table1;
END
$$
LANGUAGE plpgsql;
If I run:
SELECT * FROM my_func(99);
I guess I should receive the first 99 IDs processed for each id.
But it says there is an error for the following line:
SELECT * FROM my_func2(select * from table1 where id = i)
The error is:
The subquery is only allowed to return one column
Why does this happen? Is there an easy way to fix this?
There are multiple misconceptions here. Study the basics before you try advanced magic.
Postgres does not have "table variables". You can only pass 1 column or row at a time to a function. Use a temporary table or a refcursor (like commented by #Daniel) to pass a whole table. The syntax is invalid in multiple places, so it's unclear whether that's what you are actually trying.
Even if it is: it would probably be better to process one row at a time or rethink your approach and use a set-based operation (plain SQL) instead of passing cursors.
The data types my_part and my_part2 are undefined in your question. May be a shortcoming of the question or a problem in the test case.
You seem to expect that the table name table1 in the function body of my_func2() refers to the function parameter of the same (type!) name, but this is fundamentally wrong in at least two ways:
You can only pass values. A table name is an identifier, not a value. You would need to build a query string dynamically and execute it with EXECUTE in a plpgsql function. Try a search, many related answers her on SO. Then again, that may also not be what you wanted.
table1 in CREATE or REPLACE FUNCTION my_func2(table1) is a type name, not a parameter name. It means your function expects a value of the type table1. Obviously, you have a table of the same name, so it's supposed to be the associated row type.
The RETURN type of my_func2() must match what you actually return. Since you are returning SELECT * FROM table1, make that RETURNS SETOF table1.
It can just be a simple SQL function.
All of that put together:
CREATE or REPLACE FUNCTION my_func2(_row table1)
RETURNS SETOF table1 AS
'SELECT ($1).*' LANGUAGE sql;
Note the parentheses, which are essential for decomposing a row type. Per documentation:
The parentheses are required here to show that compositecol is a column name not a table name
But there is more ...
Don't use out as variable name, it's a keyword of the CREATE FUNCTION statement.
The syntax of your main query my_func() is more like psudo-code. Too much doesn't add up.
Proof of concept
Demo table:
CREATE TABLE table1(table1_id serial PRIMARY KEY, txt text);
INSERT INTO table1(txt) VALUES ('a'),('b'),('c'),('d'),('e'),('f'),('g');
Helper function:
CREATE or REPLACE FUNCTION my_func2(_row table1)
RETURNS SETOF table1 AS
'SELECT ($1).*' LANGUAGE sql;
Main function:
CREATE OR REPLACE FUNCTION my_func(int)
RETURNS SETOF table1 AS
$func$
DECLARE
rec table1;
BEGIN
FOR i IN 0..$1 LOOP
FOR rec IN
SELECT * FROM table1 WHERE table1_id = i
LOOP
RETURN QUERY
SELECT * FROM my_func2(rec);
END LOOP;
END LOOP;
END
$func$ LANGUAGE plpgsql;
Call:
SELECT * FROM my_func(99);
SQL Fiddle.
But it's really just a a proof of concept. Nothing useful, yet.
As the error log is telling you.. you can return only one column in a subquery, so you have to change it to
SELECT my_func2(SELECT Specific_column_you_need FROM hasval WHERE wid = i)
a possible solution can be that you pass to funct2 the primary key of the table your funct2 needs and then you can obtain the whole table by making the SELECT * inside the function

Postgresql function not returning a table on select

I have the following postgresql function in which i am trying to return 2 parameters named campusid and campusname.
CREATE OR REPLACE FUNCTION getall(IN a character varying, IN b character varying)
RETURNS TABLE(id character varying, name character varying) AS
$BODY$
BEGIN
if $1 = 'PK' then
SELECT * from table1;
end if;
END
$BODY$
LANGUAGE plpgsql;
But i am getting the following error:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function "getallcampuses" line 27 at SQL statement
********** Error **********
ERROR: query has no destination for result data
SQL state: 42601
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Context: PL/pgSQL function "getallcampuses" line 27 at SQL statement
What do i need to change in the function to make it return me a table of values? I have also checked the perform query but i need to return a result.
You must have a destination for the selects, and the function must return a value. Just a SELECT statement does neither. The only use of such a statement, generally, is to test permissions, or make a trigger run, for which the results are not used. You will need to use one of the family of RETURN statements, to get values from the function.
RETURN QUERY( SELECT * from "SIS_campus" );
That will add the results of that query to the function's returning results, and should do what you're after, since you only can return 0 or 1 results. You may need to add a simple RETURN at the very end of the function, as well (despite the docs, I've not quite grokked when that is or isn't needed, myself).

Creating functions in postgresql

I am new to SQL, so please try not to be overly critical about my question, I need to create a function which would return me a table (say for example "machine") , which would have a column called "aggtablename" and the rows would be filled with values derived from a database. Here is what i tried and the following error came....so please help me in making my syntax correct, THANKS..
CREATE FUNCTION aggtable() RETURNS TABLE (machineid, serveraggtablename)
AS $table$
BEGIN
RETURN QUERY
SELECT m.machineid, m.serveraggtablename
FROM machine m
END;
$table$
LANGUAGE plpgsql;
select aggtable();
ERROR: function aggtable() does not exist LINE 1: select aggtable();
^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
The arguments of the table you're returning do not have any type.
try adding a type such as machineid int.
check this post
How can a Postgres Stored Function return a table
Try this
CREATE TYPE machineType as (machineid int, serveraggtable character varying);
CREATE FUNCTION aggtable() RETURNS SETOF machineType AS
'SELECT m.machineid, m.serveraggtablename FROM machine m;'
LANGUAGE 'sql';
SELECT * FROM aggtable();
https://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions

Error when calling a function

I have one function that returns all employee IDs
Function definition is like this:
CREATE OR REPLACE FUNCTION tmp()
RETURNS setof record AS
$func$
begin
select emp_id from employee_master;
end;
$func$
LANGUAGE plpgsql;
But when i call this function using
select * from tmp() as abc(emp_id text);
It gives error like
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function "tmp" line 3 at SQL statement
Please give solution :)
If you want to return a rowset from a PL/PgSQL function you must use RETURN - in this case, probably RETURN QUERY:
RETURN QUERY SELECT emp_id FROM employee_master;
I don't see the point of having this in a PL/PgSQL function at all, though.
Make the function a plain SQL one as in:
...
LANGUAGE SQL;
It is much more practical to declare the actual type of the column instead of the unwieldy record type. Assuming emp_id to be integer, a simple SQL function could look like this:
CREATE OR REPLACE FUNCTION tmp()
RETURNS SETOF integer AS
$func$
SELECT emp_id FROM employee_master
$func$ LANGUAGE sql;
However, the error message in your comment does not match the given question. Depending on your actual requirements, you would adjust the RETURN type.

Convert into PostgreSQL Dynamic Query

Below is one function which has one query ,
Now I want to convert into dynamic query. I want one table name parameter so query return data from multiple tables.
please help me in this I am new in PostgreSQL , Thanks in Advance !
create or replace function GetEmployees()
returns setof weather as
'select * from weather;'
language 'sql';
This is basic PL/PgSQL. Use PL/PgSQL's EXECUTE .. USING statement and format function with the %I format-specifier.
create or replace function get_sometable(tablename regclass)
returns setof whatever_type as
BEGIN
RETURN QUERY EXECUTE format('select * from %I";', tablename);
END;
language 'plpgsql';
This will only work if all tablenames you might pass return compatible result types, as occurs with partitioning. Otherwise you'll have to return SETOF RECORD and then pass the table layout in the function invocation. See the documentation for a discussion of RECORD and SETOF RECORD.
Look into RETURNS TABLE as another convenient alternative for when the table types aren't compatible but you can still return a compatible subset via a suitable SELECT list.
If you're doing table partitioning, you should really do it as the PostgreSQL documentation on table partitioning advises, using table inheritance and triggers.
(Elaborating on Convert SQL Server stored procedure into PostgreSQL stored procedure)