I want to execute some pgScript directly from the pgAdmin editor UI.
FOR i IN 1..10 LOOP
PRINT i; -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;
But I always got
[ERROR ] 1.0: syntax error, unexpected character
I also tried to wrap the code with do$$...$$, but does not solve the problem.
apart from Clodoaldo Neto's Answer.You can try this also
DO
$$
BEGIN
FOR i IN 1..10 LOOP
RAISE NOTICE '%', i; -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;
END
$$
There is no PRINT command. Use raise notice instead.
create function f()
returns void as $$
begin
FOR i IN 1..10 LOOP
raise notice '%', i; -- i will take on the values 1,2,3,4,5,6,7,8,9,10 within the loop
END LOOP;
end;
$$ language plpgsql;
http://www.postgresql.org/docs/current/static/plpgsql.html
Related
Here's what I would like to do:
\set values foo,bar,baz
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(:'values', ',');
BEGIN
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
Which results in the following error:
ERROR: syntax error at or near ":"
SELECT string_to_array(:'values', ',') INTO values...
^
Here's the solution I have currently, but it feels hacky:
\set values foo,bar,baz
PREPARE get_values AS SELECT string_to_array(:'values', ',');
DO $$
DECLARE
value TEXT;
values TEXT[];
BEGIN
EXECUTE 'EXECUTE get_values' INTO values;
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
Answer
DO expects a string literal with plpgsql code. Symbols are not substituted inside strings in psql.
You could concatenate the whole string into a psql variable and then execute it.
How to concatenate psql variables?
Pretty multi-line format is not possible, because (per documentation):
But in any case, the arguments of a meta-command cannot continue
beyond the end of the line.
Simple example:
test=# \set value foo
test=# \set do 'BEGIN\n RAISE NOTICE ''v: %'', ' :'value' ';\nEND'
test=# DO :'do';
NOTICE: v: foo
Replace line breaks with \n (or remove them if you don't care for pretty format). Based on this adapted code:
DO
'
DECLARE
_val text;
_vals text[] := string_to_array(>>values<<, '','');
BEGIN
FOREACH _val IN ARRAY _vals
LOOP
RAISE NOTICE ''v: %'', _val;
END LOOP;
END
'
It looks like this:
test=# \set do 'DECLARE\n _val text;\n _vals text[] := string_to_array(' :'values' ', '','');\nBEGIN\n FOREACH _val IN ARRAY _vals\n LOOP\n RAISE NOTICE ''v: %'', _val;\n END LOOP;\nEND'
test=# DO :'do';
NOTICE: v: foo
NOTICE: v: bar
NOTICE: v: baz
DO
I added bold emphasis to the variable to make it easier to spot.
Related answer by #Pavel (ab)using a server session variable:
Referring to session variables (\set var='value') from PL/PGSQL
Alternative solutions
Prepared statement
Your current solution doesn't look that bad. I would simplify:
PREPARE get_values AS SELECT * FROM regexp_split_to_table(:'values', ',');
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN EXECUTE
'EXECUTE get_values'
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
Temporary table
Similar solution with a temporary table:
CREATE TEMP TABLE tmp AS SELECT * FROM regexp_split_to_table(:'values', ',') v;
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN
TABLE tmp
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
Was able to take advantage of this solution:
Passing argument to a psql procedural script
Where I set the variable as such and retrieve it with current_setting()
\set values foo,bar,baz
SET vars.values TO :'values';
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(current_setting('vars.values'), ',');
BEGIN
FOREACH value IN ARRAY values LOOP
RAISE NOTICE 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql
I tried storing the result in a varable and use coalece.
But it is not working.
do
$$
declare
v_deptno numeric := 10;
stored_empno numeric;
curempno cursor is select empno from emp e where e.deptno = v_deptno;
recempno record;
begin
open curempno;
fetch curempno
into recempno;
while found
loop
fetch curempno into recempno;
stored_empno:=recProdTest.empno;
raise info 'empno = %',coalesce(recProdTest.empno, stored_empno);
end loop;
close curempno;
end $$ language plpgsql;
Please help me.
Thanks.
Your program logic is wrong, and that won't work in Oracle either.
How many FETCH statements are executed before the first RAISE? Exactly, two: one before the loop, one in the loop.
So you are skipping the first result. The final NULL is because you don't check FOUND between FETCH and RAISE, so you report the empty result you get because the cursor is done.
Try a loop like this:
OPEN curempno;
LOOP
FETCH curempno INTO recempno;
EXIT WHEN NOT FOUND;
RAISE INFO 'empno = %', recempno.empno;
END LOOP;
I am new to PGSQL and trying to start a loop in database function that iterates on the basis of query result as shown below. I am using 8.2 version.
CREATE OR REPLACE FUNCTION demo(text)
RETURNS SETOF activityhistoryview
LANGUAGE plpgsql STABLE
AS $_$
DECLARE
tilldate ALIAS for $1;
actrec revpro_500.activity%ROWTYPE;
BEGIN
IF tilldate != '' THEN
FOR actrec IN
SELECT activity.* from revpro_500.activity WHERE activity.householdid = 950
LOOP
ELSE
FOR actrec IN
SELECT activity.* from revpro_500.activity WHERE activity.householdid = 500
LOOP
END IF;
BEGIN
/* rest code goes here */
END
END LOOP;
RETURN;
END;$_$;
After executing above function, I am getting below error.
ERROR: syntax error at or near "ELSE"
What I am missing here?
You can not nest loop queries like that. Instead, first evaluate what you want to do with tilldate, then make a single loop query:
CREATE OR REPLACE FUNCTION demo(tilldate text) RETURNS SETOF activityhistoryview
LANGUAGE plpgsql STABLE AS $_$
DECLARE
actrec revpro_500.activity%ROWTYPE;
hhid integer;
BEGIN
IF tilldate != '' THEN
hhid = 950;
ELSE
hhid = 500;
END IF;
FOR actrec IN
SELECT * from revpro_500.activity WHERE householdid = hhid
LOOP
BEGIN -- Do you really need a transaction block? If not, remove BEGIN/END
-- rest code goes here
END
END LOOP;
RETURN;
END;$_$;
Like in most languages you can't have your control structures overlapping, so on the line before the ELSE you open a LOOP, but do not close it before the ELSE, so the ELSE doesn't have an attached IF paired to it.
You can put the IF/ELSE block inside the loop, or outside it, but not overlapping.
Example:
-- Good
LOOP
-- some computations
IF tilldate != '' THEN
EXIT; -- exit loop
ELSE
-- some computations
END IF;
END LOOP;
-- Good
IF tilldate != '' THEN
LOOP
-- some computations
END LOOP;
ELSE
LOOP
-- some computations
END LOOP;
END IF;
-- Bad
IF
LOOP
-- some computations
ELSE
-- some computations
END IF;
END LOOP;
Here's what I would like to do:
\set values foo,bar,baz
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(:'values', ',');
BEGIN
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
Which results in the following error:
ERROR: syntax error at or near ":"
SELECT string_to_array(:'values', ',') INTO values...
^
Here's the solution I have currently, but it feels hacky:
\set values foo,bar,baz
PREPARE get_values AS SELECT string_to_array(:'values', ',');
DO $$
DECLARE
value TEXT;
values TEXT[];
BEGIN
EXECUTE 'EXECUTE get_values' INTO values;
FOREACH value IN ARRAY values LOOP
raise notice 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql;
Answer
DO expects a string literal with plpgsql code. Symbols are not substituted inside strings in psql.
You could concatenate the whole string into a psql variable and then execute it.
How to concatenate psql variables?
Pretty multi-line format is not possible, because (per documentation):
But in any case, the arguments of a meta-command cannot continue
beyond the end of the line.
Simple example:
test=# \set value foo
test=# \set do 'BEGIN\n RAISE NOTICE ''v: %'', ' :'value' ';\nEND'
test=# DO :'do';
NOTICE: v: foo
Replace line breaks with \n (or remove them if you don't care for pretty format). Based on this adapted code:
DO
'
DECLARE
_val text;
_vals text[] := string_to_array(>>values<<, '','');
BEGIN
FOREACH _val IN ARRAY _vals
LOOP
RAISE NOTICE ''v: %'', _val;
END LOOP;
END
'
It looks like this:
test=# \set do 'DECLARE\n _val text;\n _vals text[] := string_to_array(' :'values' ', '','');\nBEGIN\n FOREACH _val IN ARRAY _vals\n LOOP\n RAISE NOTICE ''v: %'', _val;\n END LOOP;\nEND'
test=# DO :'do';
NOTICE: v: foo
NOTICE: v: bar
NOTICE: v: baz
DO
I added bold emphasis to the variable to make it easier to spot.
Related answer by #Pavel (ab)using a server session variable:
Referring to session variables (\set var='value') from PL/PGSQL
Alternative solutions
Prepared statement
Your current solution doesn't look that bad. I would simplify:
PREPARE get_values AS SELECT * FROM regexp_split_to_table(:'values', ',');
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN EXECUTE
'EXECUTE get_values'
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
Temporary table
Similar solution with a temporary table:
CREATE TEMP TABLE tmp AS SELECT * FROM regexp_split_to_table(:'values', ',') v;
DO
$do$
DECLARE
_val text;
BEGIN
FOR _val IN
TABLE tmp
LOOP
RAISE NOTICE 'v: %', _val;
END LOOP;
END
$do$;
Was able to take advantage of this solution:
Passing argument to a psql procedural script
Where I set the variable as such and retrieve it with current_setting()
\set values foo,bar,baz
SET vars.values TO :'values';
DO $$
DECLARE
value TEXT;
values TEXT[] := string_to_array(current_setting('vars.values'), ',');
BEGIN
FOREACH value IN ARRAY values LOOP
RAISE NOTICE 'v: %', value;
END LOOP;
END $$ LANGUAGE plpgsql
This function compiled successfully:
CREATE OR REPLACE FUNCTION FieldValidations1(tbl_name varchar(35),col_name varchar(25), error_flag varchar(3))
RETURNS void AS $$
declare
cust_rec RECORD;
BEGIN
execute format($sel$
FOR cust_rec IN SELECT %I FROM %s
LOOP
RAISE NOTICE 'inside loop';
END LOOP;
$sel$,
col_name,tbl_name);
END;
$$ LANGUAGE plpgsql;
But while calling the function,
select FieldValidations1('raw_tbl1','col1','gg');
the error appears like this
ERROR: syntax error at or near "FOR"
LINE 3: FOR cust_rec IN SELECT col1 FROM raw_tbl1
^
QUERY:
FOR cust_rec IN SELECT col1 FROM raw_tbl1
LOOP
RAISE NOTICE 'inside loop';
END LOOP;
CONTEXT: PL/pgSQL function "fieldvalidations1" line 6 at EXECUTE statement
Can anyone explain what's wrong?
You must be aware that plpgsql functions are only tested on a superficial syntactical level in CREATE FUNCTION. It does not find all possible errors, it does not try to evaluate functions.
Would work like this:
CREATE OR REPLACE FUNCTION field_validations2(tbl_name text
, col_name text, error_flag text)
RETURNS void AS
$func$
DECLARE
cust_rec RECORD;
BEGIN
FOR cust_rec IN
EXECUTE format('SELECT %I FROM %I', col_name, tbl_name)
LOOP
RAISE NOTICE 'inside loop';
END LOOP;
END
$func$ LANGUAGE plpgsql;
The proper syntax for a FOR-IN-EXECUTE statement can be found in the manual.
Also fixed a couple of other things. text instead of varchar(n) is just a friendly advice.
It is not possible to execute plpgsql. It must be plain SQL.