Postgresql howto dynamically change parameter value - postgresql

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

Related

Declare type of setof bigint in plpgsql function and assign into from select union

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;

How can create one function from two functions in PostgreSQL?

I would like to create another function in PostgreSQL, function_c, from function_a and function_b.
function_a
CREATE OR REPLACE FUNCTION function_a(year_ INTEGER, col_b INTEGER)
RETURNS INTEGER AS
$$
DECLARE
vbl INTEGER;
BEGIN
SELECT COUNT(col_b) INTO vbl
FROM table1
WHERE date_part('year',table1.col_aa) = year_ AND table1.col_bb = col_b;
RETURN vbl;
END;
$$
LANGUAGE plpgsql;
function_b
CREATE OR REPLACE FUNCTION function_b(year_ INTEGER)
RETURNS INTEGER AS
$$
DECLARE
vbl_b integer;
BEGIN
SELECT COUNT(col_aa) INTO vble_b
FROM table1
WHERE date_part('year',table1.col_aa) = year_;
RETURN vbl_b
END;
$$
LANGUAGE plpgsql;
I want to create function c that including function a and b, returns:
year: year_ parameter of function_b
median: vbl of function_a divided vbl_b of function_b
How can create one function from two functions in PostgreSQL?
If I understood correctly below mentioned definition will work for you
CREATE OR REPLACE FUNCTION function_c(year_ INTEGER, col_b INTEGER)
RETURNS table (year1 integer, median numeric) AS
$$
DECLARE
var1 INTEGER;
var2 INTEGER;
var3 numeric;
BEGIN
var1=(select * from function_a(year_));
var2=(select * from function_b(year_, vol_b));
var3=var1/var2;
return query
select year_, var3;
END;
$$
LANGUAGE plpgsql;

Postgresql function loop through input arguments and append to hstore

I'm wondering if it is possibile in PostgreSQL to loop through all available input parameters of the current function and append these arguments (key=>value) to a hstore variabele.
hstore-key = the name of the given input argument/parameter....
hstore-Value = the value of the given argument...
For example:
-- input for call function with input arguments
SELECT append_hstore_from_args ('val1','val22','val333');
CREATE OR REPLACE FUNCTION append_hstore_from_args (IN param1 text, IN param2 text, IN param3 text)
RETURNS text AS
$BODY$
DECLARE
new_h hstore;
BEGIN
-- below is pseudo
for p in all_params
loop
new_h := new_h+"$p->name"=>"$p->value";
end loop;
-- at this point the variable new_h (hstore) should contain
-- '"param1"=>"val1","param2"=>"val22","param3"=>"val333"'
-- call function with hstore argument
perform test.func123(new_h);
RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
I've searched, but unfortunately didn't find any hints on how to get this done in PostgreSQL.
I assume that it is a question of how to handle a variable number of function arguments.
Variadic arguments are accessible inside a function as an array. You can use FOREACH ... LOOP:
create or replace function strings_to_hstore(args variadic text[])
returns hstore language plpgsql as $$
declare
idx int = 0;
str text;
hst hstore;
res hstore = '';
begin
foreach str in array args loop
idx:= idx+ 1;
execute format($f$select 'param%s=>%s'$f$, idx, str) into hst;
res:= res|| hst;
end loop;
return res;
end $$;
select strings_to_hstore('one', 'two');
strings_to_hstore
----------------------------------
"param1"=>"one", "param2"=>"two"
(1 row)
select strings_to_hstore('red', 'green', 'blue');
strings_to_hstore
------------------------------------------------------
"param1"=>"red", "param2"=>"green", "param3"=>"blue"
(1 row)
If you wanted to define hstore keys in the argument list:
create or replace function strings_with_keys_to_hstore(args variadic text[])
returns hstore language plpgsql as $$
declare
idx int = 0;
key text;
str text;
hst hstore;
res hstore = '';
begin
foreach str in array args loop
idx:= idx+ 1;
if idx & 1 then
key:= str;
else
execute format($f$select '%s=>%s'$f$, key, str) into hst;
res:= res|| hst;
end if;
end loop;
return res;
end $$;
select strings_with_keys_to_hstore('key1', 'val1', 'key2', 'val2');
strings_with_keys_to_hstore
--------------------------------
"key1"=>"val1", "key2"=>"val2"
(1 row)
Note, that there are standard hstore functions: hstore(text[]) and hstore(text[], text[]).

plpgsql: calling a function with 2 OUT parameters

I'm trying to fetch to values from a plpgsql function with 2 OUT paramenters but I have some problem.
These are the functions:
CREATE OR REPLACE FUNCTION get_test(OUT x text, OUT y text)
AS $$
BEGIN
x := 1;
y := 2;
END;
$$ LANGUAGE plpgsql;
----------------------------------------------------------------
CREATE OR REPLACE FUNCTION get_test_read()
RETURNS VOID AS $$
DECLARE
xx text;
yy text;
BEGIN
SELECT get_test() INTO xx, yy;
RAISE INFO 'x: <%>', xx;
RAISE INFO 'y: <%>', yy;
END;
$$ LANGUAGE plpgsql;
The output of the command:
select get_test_read();
INFO: x: <(1,2)
INFO: y: <>
get_test_read
So both the values go to the first parameter.
I cannot find some example on how to call a function like this.
As you have 2 OUT params, your function will return a record.
In order to get all values you should use function as the source of your data and put it into the FROM clause like this:
SELECT * FROM get_test() INTO xx, yy;
SELECT * INTO xx, yy FROM get_test();
UPDATE:
Explanation:
Modifying the second function:
CREATE OR REPLACE FUNCTION get_test_read()
RETURNS VOID AS $$
DECLARE
xx text;
yy text;
BEGIN
SELECT * INTO xx, yy FROM get_test();
RAISE INFO 'x: <%>', xx;
RAISE INFO 'y: <%>', yy;
END;
$$ LANGUAGE plpgsql;
This is similar to SELECT INTO with TABLE, where only get 2 values:
SELECT "FIELD1", "FIELD2" INTO variable1, variable2 FROM "TABLE" WHERE ...
Npgsql Basic Usage
PL/pgSQL Function Parameter Modes: IN, OUT, INOUT

Create a function with an argument as a subselect

I'd like to create a function for select and changed me data
CREATE OR REPLACE FUNCTION PublicatedTask( argument ) RETURNS SETOF task AS $$DECLARE
f task%ROWTYPE;
BEGIN
FOR f IN SELECT * FROM Task where layer IN $1 and publicationin<>0 ORDER BY id LOOP
if (f.publicationIN = 1) then
f.description='';
end if;
RETURN NEXT f;
END LOOP;
RETURN;
END;
$$
LANGUAGE 'plpgsql';
but I 'dont know what argument type?
I'd like to do SELECT * FROM PublicatedTask((1,2,3));
Thanks for your help
Or use VARIADIC:
CREATE OR REPLACE FUNCTION PublicatedTask( VARIADIC argument int[]) RETURNS SETOF task AS $$DECLARE
f task%ROWTYPE;
BEGIN
FOR f IN SELECT * FROM Task where layer = ANY($1) and publicationin<>0 ORDER BY id LOOP
if (f.publicationIN = 1) then
f.description='';
end if;
RETURN NEXT f;
END LOOP;
RETURN;
END;
$$
LANGUAGE 'plpgsql';
And use it this way:
SELECT * FROM PublicatedTask(1,2,3);
VARIADIC is available as of version 8.4: http://www.postgresql.org/docs/8.4/interactive/xfunc-sql.html#XFUNC-SQL-VARIADIC-FUNCTIONS
you could use an array of integers as parameter:
CREATE OR REPLACE FUNCTION PublicatedTask( argument int[]) RETURNS SETOF task AS $$DECLARE
f task%ROWTYPE;
BEGIN
FOR f IN SELECT * FROM Task where layer = ANY($1) and publicationin<>0 ORDER BY id LOOP
if (f.publicationIN = 1) then
f.description='';
end if;
RETURN NEXT f;
END LOOP;
RETURN;
END;
$$
LANGUAGE 'plpgsql';
Then you could call it this way:
SELECT * FROM PublicatedTask('{1,2,3}');