Is it possible to dynamically set param of numeric() ? eg:
CREATE OR REPLACE somefunction() RETURNS numeric AS
DECLARE
f numeric;
x integer;
BEGIN
x := 2;
SELECT INTO f CAST(something AS numeric(12, x));
RETURN f;
END;
So, I don't need to use CASE inside my plpgsql function if possible :) Tried everything, but it does not work, cast expects constant. Thanks:)
Using Dynamic query:
CREATE OR REPLACE FUNCTION public.somefunction(something numeric)
RETURNS numeric
LANGUAGE plpgsql
AS $function$
DECLARE
f numeric;
x integer;
BEGIN
x := 2;
EXECUTE 'SELECT CAST($1 AS numeric(12, ' || x ||'))' INTO f USING something;
RETURN f;
END;
$function$
;
select somefunction(126.787);
somefunction
--------------
126.79
Alternate where you pass in the scale:
CREATE OR REPLACE FUNCTION public.somefunction(something numeric, scale integer)
RETURNS numeric
LANGUAGE plpgsql
AS $function$
DECLARE
f numeric;
BEGIN
EXECUTE 'SELECT CAST($1 AS numeric(12, ' || scale ||'))' INTO f USING something;
RETURN f;
END;
$function$
;
select somefunction(126.787,2);
somefunction
--------------
126.79
(1 row)
select somefunction(126.787,1);
somefunction
--------------
126.8
The following code currently works on PostgreSQL 13.3 (via Supabase.io). Both functions get_owned_base_ids and get_bases_editable have return type of setof bigint:
CREATE FUNCTION get_owned_base_ids()
returns setof bigint
stable
language sql
as $$
select id
from bases
where bases.owner_user_id = auth.uid();
$$;
-- CREATE FUNCTION get_bases_editable()
-- returns setof bigint
-- ... similar to get_owned_base_ids()
-- $$;
CREATE FUNCTION xyz (base_id bigint)
returns int
language plpgsql
as $$
BEGIN
IF base_id not in (select get_owned_base_ids() UNION select get_bases_editable()) THEN
-- note: actual function logic is simplified for this question
return 1;
END IF;
return 0;
END;
$$;
Is it possible to define a setof bigint and assign that from the select union? Something like this:
CREATE FUNCTION xyz (base_id bigint)
returns int
language plpgsql
as $$
DECLARE
allowed_base_ids bigint; -- needs to be a setof
BEGIN
select into allowed_base_ids get_owned_base_ids() UNION select get_bases_editable();
IF kv.base_id not in allowed_base_ids THEN
-- note: actual function logic is simplified for this question
return 1;
END IF;
return 0;
END;
$$;
It usually does not make much sense and use much memory of the result set is large, but you can use an array:
DECLARE
allowed_base_ids bigint[];
BEGIN
allowed_base_ids := array(SELECT * FROM get_owned_base_ids()
UNION ALL
SELECT * FROM get_bases_editable());
IF kv.base_id <> ALL (allowed_base_ids) THEN
...
END IF;
END;
I've tried following tutorials for many times but failed.
Could someone give me some examples please?
Here is my code, it prompts that "ERROR:invalid type name 'SETOF RECORD'"
create or replace function find() returns SETOF RECORD
as $$
declare A SETOF RECORD;
begin
A=(
select x,y
from .......
)
CASE WHEN EXISTS A
THEN returns query A
ELSE returns query (
select x,y
from ......
)
END;
end;
$$ language plpgsql;
Ways to declare set returning function that I remember at the moment:
--example 1
create or replace function test() returns SETOF RECORD
as $$
begin
RETURN QUERY SELECT * FROM generate_series(1,100);
end;
$$ language plpgsql;
--test output
select * from test() AS a(b integer)
--example 2
create or replace function test2() returns TABLE (b integer)
as $$
begin
RETURN QUERY SELECT * FROM generate_series(1,100);
end;
$$ language plpgsql;
--test output
select * from test2()
--example 3
create or replace function test3() returns SETOF RECORD
as $$
declare
r record;
begin
FOR r IN SELECT * FROM generate_series(1,100) LOOP
RETURN NEXT r;
END LOOP;
end;
$$ language plpgsql;
--test output
select * from test3() AS a(b integer);
--example 4
create or replace function test4() returns setof record
as $$
SELECT * FROM generate_series(1,100)
$$ language sql;
--test output
select * from test4() AS a(b integer);
--example 5
create or replace function test5() returns setof integer
as $$
begin
RETURN QUERY SELECT * FROM generate_series(1,100);
end;
$$ language plpgsql;
--test output
select * from test5()
--example 6
create or replace function test6(OUT b integer, OUT c integer) RETURNS SETOF record
as $$
begin
RETURN QUERY SELECT b.b, b.b+3 AS c FROM generate_series(1,100) AS b(b);
end;
$$ language plpgsql;
--test output
select * from test6()
I made a function in pgadmin
create or replace function get_source2(a text)
returns integer as
$$
declare
a text;
geom geometry;
begin
select get_source(geom)
from a;
end;
$$
language plpgsql;
I want input a by table name How can I do? I try to like this
select get_source2('postgis.center')
but I get:
ERROR: relation "a" does not exist LINE 2: from a help me
try this:
create or replace function get_source2(a text)
returns integer as
$$
declare
geom geometry;
begin
execute 'select get_source(geom) from '||quote_ident(a) into geom;
return geom;
end;
$$
language plpgsql;
I have an SET of id's in a WHERE statement that gives me valid seasonal days for certain taxa id's
WHERE
...
tx_id IN ('00020','00030','00059') AND
datepart('doy',dt) IN (
SELECT TAXA_SEASON(1,'00020') UNION
SELECT TAXA_SEASON(1,'00030') UNION
SELECT TAXA_SEASON(1,'00059') )
and tax_sesion is a function for the 4 seasons I can select.
CREATE OR REPLACE FUNCTION taxa_season(SEAS INTEGER, EURING TEXT)
RETURNS SETOF INTEGER AS
$BODY$
...
$BODY$
LANGUAGE plpgsql;
Is there an functional form of union using a set or array in Postgresql
datepart('doy',dt) IN (SELECT TAXA_SEASION(1,{'00020','00030','00059'}) )
CREATE OR REPLACE FUNCTION taxa_season(SEAS INTEGER, EURINGS TEXT[])
RETURNS SETOF INTEGER AS
$BODY$
DECLARE
E TEXT;
BEGIN
FOREACH E IN ARRAY EURINGS LOOP
RETURN QUERY SELECT TAXA_SEASON(SEAS, E);
END LOOP;
RETURN;
END
$BODY$
LANGUAGE plpgsql;
Usage:
WHERE
...
tx_id = ANY(ARRAY['00020','00030','00059']) AND
datepart('doy',dt) IN (SELECT TAXA_SEASON(1,ARRAY['00020','00030','00059']) )
Upd: It was "lazy" solution does not required the changes in the existing code. The right solution is to invert the logic:
Create functions like:
CREATE OR REPLACE FUNCTION taxa_season(SEAS INTEGER, EURING TEXT[])
RETURNS SETOF INTEGER AS
$BODY$
-- Get ready to use (distinct) data for all values from EURING
$BODY$
LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION taxa_season(SEAS INTEGER, EURING TEXT)
RETURNS SETOF INTEGER AS
$BODY$
select taxa_season(SEAS, ARRAY[EURING])
$BODY$
LANGUAGE sql; -- Note that it is simple SQL function
It would be more efficiency.
Thanks #Abelisto finally it helps me out and the whole construct looks like this..
-- --------------------------------------------------------
CREATE OR REPLACE FUNCTION taxa_season(SEAS INTEGER, EURING TEXT)
RETURNS SETOF INTEGER AS
$BODY$
...find some date limits in the taxa tables
$BODY$
LANGUAGE plpgsql;
-- --------------------------------------------------------
CREATE OR REPLACE FUNCTION taxa_season(SEAS INTEGER, EURINGS TEXT[])
RETURNS SETOF INTEGER AS
$BODY$
DECLARE
E TEXT;
BEGIN
FOREACH E IN ARRAY EURINGS LOOP
RETURN QUERY SELECT TAXA_SEASON(SEAS, E);
END LOOP;
RETURN;
END
$BODY$
LANGUAGE plpgsql;
-- ----------------------------------------------
CREATE OR REPLACE FUNCTION sessions_taxa_season(
YR INTEGER,
SEAS INTEGER,
LOC TEXT,
EURINGS TEXT[])
RETURNS SETOF TEXT AS
$BODY$
DECLARE
R RECORD;
BEGIN
IF SEAS > 0 AND SEAS < 4 THEN
FOR R IN
SELECT DISTINCT session
FROM sync_utm32
WHERE
date_part('doy', gps_dt)
IN (SELECT DISTINCT TAXA_SEASON(SEAS, EURINGS)) AND
date_part('year', gps_dt) = YR AND
session ~~ LOC
ORDER BY SESSION
LOOP
RETURN NEXT R.SESSION;
END LOOP;
END IF;
IF SEAS=4 THEN
FOR R IN
SELECT DISTINCT SESSION
FROM sync_utm32
WHERE
date_part('doy', gps_dt)
IN (SELECT DISTINCT TAXA_SEASON(SEAS, EURINGS)) AND
date_part('year', gps_dt) = YR-1 AND
date_part('doy', gps_dt) >= 365/2 AND
session ~~ LOC
ORDER BY SESSION
LOOP
RETURN NEXT R.SESSION;
END LOOP;
FOR R IN
SELECT DISTINCT SESSION
FROM sync_utm32
WHERE
date_part('doy', gps_dt)
IN (SELECT DISTINCT TAXA_SEASON(SEAS, EURINGS)) AND
date_part('year', gps_dt) = YR AND
date_part('doy', gps_dt) < 365/2 AND
session ~~ LOC
LOOP
RETURN NEXT R.SESSION;
END LOOP;
END IF;
RETURN;
END
$BODY$
LANGUAGE plpgsql;
Result of request:
SELECT SESSIONS_TAXA_SEASON(2016, 4,'%XX',ARRAY['00020','00030','00059']);
sessions_taxa_season
----------------------
2015-11-01-XX
2015-12-07-XX
2016-02-16-XX
2016-01-21-XX
The rest is sprintf template driven from perl DBI.