Functions with tablename as argument in postgresql - postgresql

How to create a function in postgresql with tablename as argument and the function returns the result set of table which is passed as argument for the query "select * from TABLE". Here the TABLE is the argument passed to the function.

What you want is possible but completely and utterly useless.
The function you were asking for is this:
CREATE FUNCTION selectall(tbl name) RETURNS SETOF record AS $$
BEGIN
RETURN QUERY EXECUTE format('SELECT * FROM %I', tbl);
END;
$$ LANGUAGE plpgsql;
You need a set returning function (SRF) because a table may have multiple rows. It needs to return record because different tables return different sets of columns. You can not use this SRF in a select list:
test=# SELECT selectall('student');
ERROR: set-valued function called in context that cannot accept a set
CONTEXT: PL/pgSQL function selectall(name) line 3 at RETURN QUERY
You can use it as a row source, but then the query becomes longer than a simple SELECT * FROM student. You can not use it just like so:
test=# SELECT * FROM selectall('student');
ERROR: a column definition list is required for functions returning "record"
LINE 1: SELECT * FROM selectall('student');
You can only use it by specifying an alias and column definitions:
test=# SELECT * FROM selectall('student') AS t(id int, first_name text, col3 boolean, ...);
Now compare that to:
test=# SELECT * FROM student;

Related

stored procedure with parameter in pgadmin

I am trying to create a stored procedure via pgadmin4. I have a actors table with one of the columns being gender with the data type as character either M or F, so what I want to create is stored procedure where I supply the gender as a single char 'M' or 'F'
This is my code:
CREATE or replace PROCEDURE actorGender(sex character)
language plpgsql
as $$
begin
select * from actors where gender = sex;
end;$$
call actorGender('M')
But I get 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 actorgender(character) line 3 at SQL statement SQL
state: 42601
db fiddle But I don't know how to decompose it.
PROCEDURE when you call it, you also need to specify all the IN and OUT. unlike the function. you can just call it with select function(in argument).
begin;
create table actors(actorid bigint, gender text,actorname text);
insert into actors (actorid, gender, actorname) values (1,'hi', 'etc');
insert into actors (actorid, gender, actorname) values (2,'hello', 'etc1');
commit;
CREATE or replace PROCEDURE actorgender(in sex text, out a actors)
language plpgsql
as $$
begin
select * from actors where gender = sex into a;
end
$$;
call it with INPUT and OUTPUT parameter.
call actorgender('hi',null::actors);
It will return (1,hi,etc)
use function would be must easier.
https://www.postgresql.org/docs/current/xfunc-sql.html#XFUNC-SQL-FUNCTIONS-RETURNING-TABLE
CREATE FUNCTION getactors(text) RETURNS SETOF actors AS $$
SELECT * FROM actors WHERE gender = $1;
$$ LANGUAGE SQL;
--call it
SELECT * FROM getactors('hi') AS t1;

PostgreSQL function taking column name as argument

I have a table tab1 with four columns col1, col2, col3 and col4.
I want to create a function like f4(a) where a is defined by user and if user types select f4(col1) he gets column tab1.col1.
Is there any way to create such function in PostgreSQL?
There is really not good reason to complicate matters with a function here.
What you should do instead:
SELECT col1 FROM tab1;
What you ask for:
CREATE OR REPLACE FUNCTION f4(_col text)
RETURNS TABLE (col_x text)
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE
format('SELECT %I FROM tab1', _col);
END
$func$;
Call:
SELECT * FROM f4('col1');
You need dynamic SQL because SQL does not allow to parameterize identifiers.
Further reading:
Using variable for fieldname in postgresql
Define table and column names as arguments in a plpgsql function?

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 $$ $$

PostgreSQL: How to display only selected columns of a single table within CASE expression in function?

Example: I am passing two parameters to function namely n(case number) and tname(table name), and want to display rows accordingly.
--Table "testing"
create table testing
(
rollno integer,
fname text,
lname text,
age integer,
branch text,
phno integer,
email text,
address text,
city text,
state text,
country text
)
--Rows insertion
insert into testing values(1,'aaa','bbb',25,'CS',1234567890,'abc#gmail.com','sector1','xyz','zyx','yxz');
insert into testing values(2,'zzz','xxx',25,'EE',987654321,'zzz#gmail.com','sector2','uvw','wvu','vuw');
--Function "f1()"
create or replace function f1(n integer,tname varchar)/*n for case number and tname for table name */
returns setof tname as
$body$
begin
case n
when 1 then
return query execute format ($$ select rollno,fname from %I $$,tname);
when 2 then
return query execute format ($$ select lname,age,branch from %I $$,tname);
when 3 then
return query execute format ($$ select phno,email,address,city,country from %I $$,tname);
end case;
end
$body$
language plpgsql;
--Function calling
select * from f1(1,'testing');
/*Show only case "1" select query result*/
select * from f1(2,'testing');
/*Show only case "2" select query result*/
select * from f1(3,'testing');
/*Show only case "3" select query result*/
While Craig is correct that return types cannot be dynamic in function declarations, there is a way around this with polymorphic types. This is surprisingly simple and would actually work flawlessly:
CREATE OR REPLACE FUNCTION data_of(_tbl_type anyelement)
RETURNS SETOF anyelement AS
$func$
BEGIN
RETURN QUERY EXECUTE 'SELECT * FROM '|| pg_typeof(_tbl_type);
END
$func$ LANGUAGE plpgsql;
Call (important!):
SELECT rollno,fname FROM data_of(NULL::testing);
SELECT * FROM data_of(NULL::my_schema.my_table);
SELECT * FROM data_of(NULL::my_custom_type);
What you need is a well-known type. For every table there is a well-known type automatically. But you can create any type, cast NULL to it and pass it to the function. This way you can build exactly what you have in your question ...
Related answer with a lot more details:
Refactor a PL/pgSQL function to return the output of various SELECT queries

Calling set-returning function with each element in array

I have a set-returning function (SRF) that accepts an integer argument and returns a set of rows from a table. I call it using SELECT * FROM tst.mySRF(3);, and then manipulate the returned value as if it were a table.
What I would like to do is to execute it on each element of an array; however, when I call it using SELECT * FROM tst.mySRF(unnest(array[3,4]));, an error is returned "set-valued function called in context that cannot accept a set". If I instead call it using SELECT tst.mySRF(unnest(array[3,4]));, I get a set of the type tst.tbl.
Table definition:
DROP TABLE tst.tbl CASCADE;
CREATE TABLE tst.tbl (
id serial NOT NULL,
txt text NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO tst.tbl(txt) VALUES ('a'), ('b'), ('c'), ('d');
Function definition:
CREATE OR REPLACE FUNCTION tst.mySRF(
IN p_id integer
)
RETURNS setof tst.tbl
LANGUAGE plpgsql
AS $body$
DECLARE
BEGIN
RETURN QUERY
SELECT id, txt
FROM tst.tbl
WHERE id = p_id;
END;
$body$;
Calls:
SELECT * FROM tst.mySRF(3) returns a table, as expected.
SELECT tst.mySRF(unnest(array[3,4])) returns a table with a single column of the type tst.tbl, as expected.
SELECT * FROM tst.mySRF(unnest(array[3,4])) returns the error described above, I had expected a table.
To avoid the "table of single column" problem, you need to explicitly expand the SRF results with the (row).* notation
SELECT (tst.mySRF(unnest(array[3,4]))).*;
If I understood #depesz, LATERAL will provide a more efficient or straightforward way to achieve the same result.