Here I am trying to concatenate a string with ,:
CREATE FUNCTION looping() RETURNS TABLE(round text)
DECLARE
i RECORD;
BEGIN
FOR i IN select regexp_split_to_table('33,55,66,88', ',') as "asd"
LOOP
str:= str || ',' ||(select i."asd");
END LOOP;
END;
$$ LANGUAGE plpgsql;
Is it true or am I missing something?
Often, a set-based operation with standard SQL functions is superior to looping.
But if you need the control structure in plpgsql, would work like this (one of many ways):
CREATE FUNCTION f_loop2(OUT str text)
RETURNS text AS
$func$
DECLARE
i text;
BEGIN
str := '';
FOR i IN
SELECT regexp_split_to_table('33,55,66,88', ',')
LOOP
str := str || ',' || i;
END LOOP;
END
$func$ LANGUAGE plpgsql;
Related
I have a function that takes 3 parameters: huc, id_list, and email.
CREATE OR REPLACE FUNCTION my_app.job_batch(
huc text,
input_list text[],
email text
) RETURNS VOID AS
$$
DECLARE
id text;
BEGIN
FOREACH id IN ARRAY input_list LOOP
EXECUTE 'SELECT * FROM my_app.my_funct(
' || huc || '::text,
' || id || '::text,
' || email || '::text)';
END LOOP;
END;
$$
LANGUAGE plpgsql;
When I try to run the function however, it throws an error: ERROR: column "myhu4" does not exist
SELECT * FROM spg_app.append_spg_job_batch('MYHUC4', array['1021', '1025','1026','1027','0701','0702','0703','0708','0709'], 'myemail#gmail.com');
Why is it referring to myhuc4 as a column and why is displaying it in lower case. Is my syntax below to run the function with those 3 parameters incorrect? Note: If I run the below hardcoded version, it runs fine:
DO $$
DECLARE
id_list text[] := array['1021', '1025','1026','1027','0701','0702','0703','0708','0709'];
id text;
BEGIN
FOREACH id in ARRAY id_list LOOP
EXECUTE 'SELECT * FROM my_app.my_funct(
''MYHU4''::text,
' || id || '::text,
''myemail#gmail.com''::text)'
END LOOP;
END;
$$
LANGUAGE plpgsql;
I suggest to use parameters instead of bad practice of stitching strings, as follows:
CREATE OR REPLACE FUNCTION my_app.job_batch(
huc text,
input_list text[],
email text
) RETURNS VOID AS
$$
DECLARE
id text;
BEGIN
FOREACH id IN ARRAY input_list LOOP
execute format ('SELECT * FROM my_app.my_funct($1, $2, $3)')
using huc, id, email;
END LOOP;
END;
$$
LANGUAGE plpgsql;
as shown in official docs https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
i am trying to check if a element is present in an array using plpgsql.
and i am receiving "array subscript must have integer" error while executing the function.
select test('IND') should return true and select test('ING') should return false
Below is the code
create or replace function test(country varchar)
returns varchar
language plpgsql
AS $function$
declare
results varchar;
countryarr varchar[3];
i varchar[];
begin
countryarr := array['IND','USA','MEX'];
foreach i slice 1 in array countryarr
loop
if countryarr[i]=country
then results := 'TRUE';
else
results := 'FALSE';
end if;
end loop;
return results;
end;
$function$
;
Your i is defined as a varchar[] in your code. It cannot be used as an integer.
You want something like this:
create or replace function test(country varchar)
returns varchar
language plpgsql
AS $function$
declare
countryarr varchar[3];
i text;
begin
countryarr := array['IND','USA','MEX'];
foreach i in array countryarr
loop
if i = country
then return 'TRUE';
end if;
end loop;
return 'FALSE';
end;
$function$
;
A better solution for what you are trying to achieve is:
create or replace function test(country varchar)
returns varchar
language sql
AS $function$
select case
when country = any(array['IND', 'USA', 'MEX']) then 'TRUE'
else 'FALSE'
end;
$function$;
Let your function return a boolean. Then it reduces to a single SQL statement.
create or replace function is_valid_country(country_in varchar)
returns boolean
language sql
immutable strict
AS $$
select country_in = any(array['IND', 'USA', 'MEX']) ;
$$;
with test(country) as
( values ('IND'), ('USA'), ('MEX'), ('CAN'),('UK') )
select country, is_valid_country(country) is_valid
from test;
This can be used in any subsequent sql statement. And the optimizer can in-line it.
I have a bytea column in a table that contains a function decode(). What I have done to get the actual data is as follows:
select filename, convert_from(data,'UTF-8') from attachments limit 20; //this returns me decode function
select decode(E'...','hex'); // I am executing the above returned function
The above is fine as long as I have to select one row. But now my requirement is to get more than one result. How can I get the result in single query? I have tried using pl/pgsql
CREATE OR REPLACE FUNCTION get_data(integer, _type anyelement, OUT _result anyelement)
AS
$x$
BEGIN
EXECUTE
'SELECT ' || (select convert_from(data,'UTF-8') as data from attachments limit $1)
INTO _result;
END;
$x$
LANGUAGE plpgsql;
But this works only for single row and single column. What I want is a single query to fetch 2 columns without using pl/pgsql if possible. I am using this query from my Java based web app.
Thanks!
You need procedural code for this, since there is no provision for dynamic statements in SQL.
The following function converts all attachments:
CREATE FUNCTION getemall(
IN v_type anyelement,
OUT v_result anyelement
) RETURNS SETOF anyelement
LANGUAGE plpgsql AS
$$DECLARE
v_stmt text;
BEGIN
FOR v_stmt IN
SELECT convert_from(data,'UTF-8')
FROM attachments
LOOP
EXECUTE v_stmt INTO v_result;
RETURN NEXT;
END LOOP;
END;$$;
This is how I have written the function with few changes
CREATE OR REPLACE FUNCTION getmeall(tName text, fNameCol text, dataCol text,fSize
numeric)
RETURNS TABLE(bdata bytea, fname text) LANGUAGE plpgsql AS
$$DECLARE
v_stmt text;
v_name text;
BEGIN
FOR v_stmt,v_name IN
EXECUTE format('SELECT encode(%s, ''escape''), %s FROM %s
WHERE $1 IS NOT NULL AND $2 IS NOT NULL LIMIT $3'
, dataCol, fNameCol, tName)
USING dataCol, fNameCol, fSize
LOOP
fname:=v_name;
IF strpos(v_stmt,'decode') = 1 THEN
EXECUTE 'SELECT ' || v_stmt INTO bdata;
ELSE
bdata:=v_stmt;
END IF;
RETURN NEXT;
END LOOP;
END;$$;
And finally calling it this way.
select * from getmeall('attachments', '"filename"', '"data"',2)
I've a PostgreSQL function that returns a string. I want to use this function into another one but I obtain an error.
These are the sample functions, with get_some_string that returns text, and use_the_string where I want to call the previous one and store the result in a variable:
CREATE OR REPLACE FUNCTION public.get_some_string()
RETURNS text AS
$func$
DECLARE
BEGIN
return 'mystring';
END
$func$ LANGUAGE plpgsql VOLATILE;
CREATE OR REPLACE FUNCTION public.use_the_string()
RETURNS boolean AS
$func$
DECLARE
mytext text;
BEGIN
mytext := select public.get_some_string();
END
$func$ LANGUAGE plpgsql VOLATILE;
If I run this query I obtain the error:
ERROR: syntax error at or near "select"
LINE 24: mytext := select public.get_some_string();
What I'm doing wrong? How can I use the return value of the first function into the second one?
You don't need a select:
CREATE OR REPLACE FUNCTION public.use_the_string()
RETURNS boolean AS
$func$
DECLARE
mytext text;
BEGIN
mytext := public.get_some_string();
END
$func$ LANGUAGE plpgsql VOLATILE;
The second one must be:
RETURNS boolean AS
$func$
DECLARE
mytext text;
BEGIN
select public.get_some_string() into mytext;
END
$func$ LANGUAGE plpgsql VOLATILE;
or
mytext := (select public.get_some_string());
or
mytext := public.get_some_string();
Note to other answers: select is implicitly added in plpgsql context. Example:
do $$
declare
v text[];
begin
v := array_agg(datname) from pg_database;
raise info 'List of databases: %', v;
end $$;
So when you call mytext := select public.get_some_string(); it is transformed to select select public.get_some_string(); internally.
Thats why parenthesesis mytext := (select public.get_some_string()); could be the solution: select (select public.get_some_string()); is the acceptable statement.
I am trying to run the code:
CREATE OR REPLACE FUNCTION anly_work_tbls.testfncjh (tablename text) returns int
AS $$
DECLARE
counter int;
rec record;
tname text;
BEGIN
counter = 0;
tname := tablename;
FOR rec IN
select *
from tname
loop
counter = counter + 1;
end loop;
RETURN counter;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE
SECURITY DEFINER;
The goal of this code is to return the number of rows in the table you input. I know that this might not be the best way to accomplish this task, but the structure of this function would extend nicely to another question I am trying to tackle. Every time I run the code, I get the error:
ERROR: syntax error at or near "$1"
All online resources I have found tell me how to use the input variable within and EXECUTE block, but not in the above situation.
Currently running PostgreSQL 8.2.15.
CREATE OR REPLACE FUNCTION anly_work_tbls.testfncjh (tbl regclass, OUT row_ct int) AS
$func$
BEGIN
EXECUTE 'SELECT count(*) FROM '|| tbl
INTO row_ct;
END
$func$ LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER;
Call:
SELECT anly_work_tbls.testfncjh('anly_work_tbls.text_tbl');
This should work for Postgres 8.2, but you consider upgrading to a current version anyway.
I pass the table name as object identifier type regclass, which takes care of quoting automatically and works with schema-qualified names. Details:
Table name as a PostgreSQL function parameter
Using an OUT parameter simplifies the function.
Don't quote the language name. It's an identifier.
If you actually need to loop through the result of a dynamic query:
CREATE OR REPLACE FUNCTION anly_work_tbls.testfncjh (tbl regclass)
RETURNS int AS
$func$
DECLARE
counter int := 0; -- init at declaration time
rec record;
BEGIN
FOR rec IN EXECUTE
'SELECT * FROM ' || tbl
LOOP
counter := counter + 1; -- placeholder for some serious action
END LOOP;
RETURN counter;
END
$func$ LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER;
Read this chapter in the manual: Looping Through Query Results
The documented assignment operator in plpgsql is :=:
The forgotten assignment operator "=" and the commonplace ":="
Yes is really not the best way, but this would work:
CREATE OR REPLACE FUNCTION testfncjh (tablename text) returns int
AS $$
DECLARE
counter int;
rec record;
BEGIN
counter = 0;
FOR rec IN
EXECUTE 'select * from '||quote_ident(tablename) loop
counter = counter + 1;
end loop;
RETURN counter;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE
SECURITY DEFINER;
This would be nicer:
CREATE OR REPLACE FUNCTION testfncjh (tablename text) returns int
AS $$
DECLARE _count INT;
BEGIN
EXECUTE 'SELECT count(*) FROM '|| quote_ident(tablename) INTO _count;
RETURN _count;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE
SECURITY DEFINER;