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[]).
Related
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
I'm a beginner in plpgsql and working on a project which requires me to write a function that returns two variables in the form of 2 columns (res,Result). I've done a quite a bit of searching but didn't find answer for the same. The reference to my code is below
CREATE OR REPLACE FUNCTION propID(character varying)
RETURNS SETOF RECORD AS $val$
DECLARE
t_row record;
res BOOLEAN;
result character varying;
value record;
BEGIN
FOR t_row IN SELECT property_id FROM property_table WHERE ward_id::TEXT = $1 LOOP
RAISE NOTICE 'Analyzing %', t_row;
res := false; -- here i'm going to replace this value with a function whos return type is boolean in future
result := t_row.property_id;
return next result; --here i want to return 2 variables (res,result) in the form of two columns (id,value)
END LOOP;
END;
$val$
language plpgsql;
Any help on the above query would be very much appreciated.
Assuming that property_id and ward_id are integers you can achieve your goal in a simple query like this:
select some_function_returning_boolean(property_id), property_id
from property_table
where ward_id = 1; -- input parameter
If you absolutely need a function, it can be an SQL function like
create or replace function prop_id(integer)
returns table (res boolean, id int) language sql
as $$
select some_function_returning_boolean(property_id), property_id
from property_table
where ward_id = $1
$$;
In a plpgsql function you should use return query:
create or replace function prop_id(integer)
returns table (res boolean, id int) language plpgsql
as $$
begin
return query
select some_function_returning_boolean(property_id), property_id
from property_table
where ward_id = $1;
end
$$;
Need Output from table with in clause in PostgreSQL
I tried to make loop or ids passed from my code. I did same to update the rows dynamically, but for select I m not getting values from DB
CREATE OR REPLACE FUNCTION dashboard.rspgetpendingdispatchbyaccountgroupidandbranchid(
IN accountgroupIdCol numeric(8,0),
IN branchidcol character varying
)
RETURNS void
AS
$$
DECLARE
ArrayText text[];
i int;
BEGIN
select string_to_array(branchidcol, ',') into ArrayText;
i := 1;
loop
if i > array_upper(ArrayText, 1) then
exit;
else
SELECT
pd.branchid,pd.totallr,pd.totalarticle,pd.totalweight,
pd.totalamount
FROM dashboard.pendingdispatch AS pd
WHERE
pd.accountgroupid = accountgroupIdCol AND pd.branchid IN(ArrayText[i]::numeric);
i := i + 1;
end if;
END LOOP;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;
There is no need for a loop (or PL/pgSQL actually)
You can use the array directly in the query, e.g.:
where pd.branchid = any (string_to_array(branchidcol, ','));
But your function does not return anything, so obviously you won't get a result.
If you want to return the result of that SELECT query, you need to define the function as returns table (...) and then use return query - or even better make it a SQL function:
CREATE OR REPLACE FUNCTION dashboard.rspgetpendingdispatchbyaccountgroupidandbranchid(
IN accountgroupIdCol numeric(8,0),
IN branchidcol character varying )
RETURNS table(branchid integer, totallr integer, totalarticle integer, totalweight numeric, totalamount integer)
AS
$$
SELECT pd.branchid,pd.totallr,pd.totalarticle,pd.totalweight, pd.totalamount
FROM dashboard.pendingdispatch AS pd
WHERE pd.accountgroupid = accountgroupIdCol
AND pd.branchid = any (string_to_array(branchidcol, ',')::numeric[]);
$$
LANGUAGE sql
VOLATILE;
Note that I guessed the data types for the columns of the query based on their names. You have to adjust the line with returns table (...) to match the data types of the select columns.
I am new to PostgreSQL. I have the query:
---------
DO
$$
DECLARE
l_pin INT;
l_pin1 int;
BEGIN
l_pin := 3;
l_pin1 := 4;
select l_pin,l_pin1;
END;
$$
LANGUAGE PLPGSQL;
--------------------------
from above query am getting an error as
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 inline_code_block line 9 at SQL statement
SQL state: 42601
I need to get the values of l_pin and l_pin1 as output.
What you have there is a DO statement, not a "query" nor a "function". DO statements cannot return anything at all.
How to perform a select query in a DO block?
The displayed error is because you cannot call SELECT in a plpgsql code block without assigning the result. To actually return values from a plpgsql function, use some form of RETURN (explicitly or implicitly).
As minimal example:
CREATE OR REPLACE FUNCTION foo(OUT l_pin int, OUT l_pin1 int)
RETURNS record AS -- RETURNS record is optional because of OUT parameters
$func$
BEGIN
l_pin := 3;
l_pin1 := 4;
RETURN; -- RETURN is optional here because of OUT parameters
END
$func$ LANGUAGE plpgsql;
SELECT * FROM foo();
Related:
Can I make a plpgsql function return an integer without using a variable?
SELECT or PERFORM in a PL/pgSQL function
Returning from a function with OUT parameter
First you can create a new type that can hold multiple values:
CREATE TYPE type_name AS (l_pin INTEGER, l_pin1 INTEGER);
Then you can do something like:
CREATE OR REPLACE FUNCTION function_name()
RETURNS type_name AS $$
DECLARE
result type_name;
BEGIN
/* Code that puts those values into type_name object
i.e.
result.l_pin := 3;
result.l_pin1 := 4;
*/
return result ;
END
$$ language plpgsql
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}');