I have written a SQL function in PostgreSQL that accesses data from another table. On running the function, I am getting following error
relation table2 does not exist postgres
Here is the function that I am creating
CREATE OR REPLACE FUNCTION func(tbl1 table1)
RETURNS TABLE(a int, b text, c int, d text) AS $$
SELECT a, b, c, d
FROM table2
WHERE id = tbl1.user_id;
$$
language sql stable;
Working in case I change table2 to myschema.table2
What do I do? I do not want to add schema into the query. I want it to take whatever schema the function is in.
imitate 38.5.3. SQL Functions on Composite Types (https://www.postgresql.org/docs/current/xfunc-sql.html#XFUNC-SQL-FUNCTION-ARGUMENTS)
db fiddle
CREATE OR REPLACE FUNCTION func(table1)
RETURNS TABLE(a int, b text, c int, d text) AS $$
SELECT a, b, c, d FROM table2 WHERE id = $1.user_id;
$$
language sql;
call it. select (func(table1.*)).* from table1;
Related
I have a postgres DB and I want to create a function that returns a copy of my table with a new column that has a value of 1 if its id is inside the array(idds[]) that the function gets as an input.
In the code below I've try to create a temporary table(chosen) that have id if it's in the idds array and to manually add the isChosen column that obviously doesn't work...
CREATE OR REPLACE FUNCTION public.getTableFromArray(idds integer[])
RETURNS table(
id INTEGER,
isChosen INTEGER
)
LANGUAGE 'plpgsql'
AS $BODY$
begin
with chosen AS(SELECT id,isChosen=1 FROM table1 WHERE ARRAY[table1.id] <# idds)
return query
SELECT id FROM table1 LEFT JOIN chosen ON table1.id=chosen.id;
end;
$BODY$;
Or, with a lot less noise, a proper boolean output column, and without the unhelpful CaMeL case identifiers in a plain SQL function:
CREATE OR REPLACE FUNCTION public.get_table_from_array(idds integer[])
RETURNS TABLE(id int, is_chosen bool)
LANGUAGE sql AS
'SELECT t.id, t.id = ANY(idds) FROM table1 t';
Might as well just run the SQL command directly, though:
SELECT id, id = ANY('{1,2,3}'::int[]) AS is_chosen FROM table1;
you can use this query instead :
select * , case when ARRAY[table1.id] <# idds then 1 else 0 end as choosen FROM table1;
so:
CREATE OR REPLACE FUNCTION public.getTableFromArray(idds integer[])
RETURNS table(
id INTEGER,
isChosen INTEGER
)
LANGUAGE 'plpgsql'
AS $BODY$
begin
return query
select id , case when ARRAY[table1.id] <# idds then 1 else 0 end as isChosen FROM table1;
end;
$BODY$;
I have a basic stored procedure for a select statement. The select statement by itself works and shows me the data output, but when I try calling it from a stored procedure, it says 'CALL Query returned successfully in 107 msec', but there's no data output. Is there something that I'm missing from my stored procedure?
(I'm also connecting a database on AWS with the basic tier, not sure if that makes a difference. Every other CRUD operation works except for select.)
CREATE PROCEDURE
experiment1()
LANGUAGE SQL
AS $$
SELECT * FROM assignment
$$
A Postgres procedure does not return anything. You can use a function instead, with the return query syntax. This requires enumerating the columns that the query returns. Assuming that your table has two columns, id and val, that would be:
create function experiment()
returns table (id int, val text)
as $$
begin
return query select * from assignment;
end;
$$ language plpgsql;
You can then invoke this set-returning function like so:
select * from experiment();
Demo on DB Fiddle:
create table assignment (id int, val text);
insert into assignment values(1, 'foo'), (2, 'bar');
-- 2 rows affected
create function experiment()
returns table (id int, val text)
as $$
begin
return query select * from assignment;
end;
$$ language plpgsql;
select * from experiment();
id | val
-: | :--
1 | foo
2 | bar
What's the difference between a function that returns TABLE vs SETOF records, all else equal.
CREATE FUNCTION events_by_type_1(text) RETURNS TABLE(id bigint, name text) AS $$
SELECT id, name FROM events WHERE type = $1;
$$ LANGUAGE SQL STABLE;
CREATE FUNCTION events_by_type_2(text) RETURNS SETOF record AS $$
SELECT id, name FROM events WHERE type = $1;
$$ LANGUAGE SQL STABLE;
These functions seem to return the same results. See this SQLFiddle.
When returning SETOF record the output columns are not typed and not named. Thus this form can't be used directly in a FROM clause as if it was a subquery or a table.
That is, when issuing:
SELECT * from events_by_type_2('social');
we get this error:
ERROR: a column definition list is required for functions returning
"record"
It can be "casted" into the correct column types by the SQL caller though. This form does work:
SELECT * from events_by_type_2('social') as (id bigint, name text);
and results in:
id | name
----+----------------
1 | Dance Party
2 | Happy Hour
...
For this reason SETOF record is considered less practical. It should be used only when the column types of the results are not known in advance.
This answer is only to remember alternative context where TABLE and SETOF are equivalent.
As #a_horse_with_no_name pointed, it is not a RETURNS SETOF "unknown record", is a defined one.
In this example, the types table and setof are equivalent,
CREATE TYPE footype AS (score int, term text);
CREATE FUNCTION foo() RETURNS SETOF footype AS $$
SELECT * FROM ( VALUES (1,'hello!'), (2,'Bye') ) t;
$$ language SQL immutable;
CREATE FUNCTION foo_tab() RETURNS TABLE (score int, term text) AS $$
SELECT * FROM ( VALUES (1,'hello!'), (2,'Bye') ) t;
$$ language SQL immutable;
SELECT * FROM foo(); -- works fine!
SELECT * FROM foo_tab(); -- works fine and is equivalent.
The RETURNS SETOF have the advantage of reuse type (see footype), that is impossible with RETURNS TABLE.
I have this in a stored proc in SQL Server:
if not exists
(my select statement)
insert T
(a, b, c)
values
(v_a, v_b, v_c) -- arguments passed to the function
select a,b,c from T where...; -- return the row to the client after inserting it
Does postgreSQL have a counterpart to that if exists ( {select-statement} ) construct? The plpgsql compiler at first told me there was a missing "THEN" but when I corrected the if ... then syntax:
create function foo(v_a int, v_b int, v_c int)
returns TABLE (a int, b int, c int)
as $body$
begin
if not exists
(select id from T where ...) then
insert into T
(a, b, c)
values
(v_a, v_b, v_c);
return QUERY
select a,b,c from T where ... ;
end
$body$
LANGUAGE 'plpgsql'
the compilation terminates with:
ERROR: syntax error at end of input
LINE 52: $body$ LANGUAGE 'plpgsql'
.........^
so I'm assuming there's some error upstream, but I don't see it.
Your IF clause is incomplete. It must be closed by the corresponding END IF statement.
Check the docs on conditionals.
I'd like to define a function in PostgreSQL 9.1 that takes multiple INOUT parameters of composite types, but I don't know how to call it.
Eg.
CREATE TYPE my_type_a AS (a integer, b float);
CREATE TYPE my_type_b AS (c boolean, d varchar(5));
CREATE FUNCTION my_complex_func(INOUT a my_type_a, INOUT b my_type_b)
RETURNS RECORD
'...'
LANGUAGE plpgsql;
The definition statements execute just fine, but I don't know how to call this function! I tried:
SELECT INTO a, b
a, b FROM my_complex_func(a, b);
but this gives an error:
ERROR: record or row variable cannot be part of multiple-item INTO list
I don't think it has anything to do with your input types, or the number of them.
Don't return a RECORD, return a real composite type (defined with CREATE TYPE).
The error record or row variable cannot be part of multiple-item INTO list is because you're trying to nest a ROW inside another ROW.
This should work:
CREATE TYPE my_type_a AS (a integer, b float);
CREATE TYPE my_type_b AS (c boolean, d varchar(5));
CREATE TYPE ret_type AS (w integer, v boolean);
CREATE FUNCTION my_complex_func(INOUT a my_type_a, INOUT b my_type_b)
RETURNS ret_type as $$
...
$$ LANGUAGE plpgsql;
And then you can do:
SELECT INTO a, b
(x.comp).w, (x.comp).v
FROM (select my_complex_func(j, i) as comp) x;
This concrete example works for me:
create type smelly1 as (a integer, b text);
create type smelly2 as (a boolean, b float);
create type rettype as (w integer, v boolean);
create function foo_func(n smelly1, m smelly2) returns rettype as $$
declare
f_ret rettype;
begin
f_ret.w := n.a;
f_ret.v := m.a;
return f_ret;
end;
$$ language plpgsql;
select (x.comp).w, (x.comp).v from
(select foo_func('(4, hello)'::smelly1, '(true,3.14)'::smelly2) as comp) x;
returns:
w | v
---+---
4 | t
(1 row)