I have a syntax error on a procedure (PostgreSQL) and I can't find the mistake. I need a procedure with the variable declaration, a for loop, and a transaction.
Here is a sample of the structure I'm using.
CREATE OR REPLACE PROCEDURE repor_dados()
LANGUAGE plpgsql AS
$$
DECLARE
utilizador int;
data_acesso date;
r record;
BEGIN
BEGIN -- begin transaction
select 2 ,4 into data_acesso,utilizador;
IF EXISTS(select 2) then -- condition
BEGIN
-- for each select result
FOR r IN SELECT 1,2,3
LOOP
-- do something
IF r = 1 THEN
SELECT 3;
ELSE
SELECT 4;
END IF;
END LOOP;
END;
COMMIT; -- commit transaction
END
$$
I am working with PostgreSQL 13.2.
The error is:
ERROR: syntax error at end of input LINE 30: $$
Related
How can we replace the plsql code with count to postgresql
FOR I IN 1..variable.count
Loop
Cr:= varray (i)
End loop;
Replacement for count in postgresql
This can be executed like a normal query :
$$ declares a string works same as '' ,example: SELECT $$string$$; or SELECT $string$ 'text' $string$;
DO indicate the next string will be executed.
DO
$$
DECLARE
rRecord RECORD;
tText TEXT ;
BEGIN
FOR rRecord IN SELECT COUNT(*) FROM generate_series(1 , 10 , 1 )
LOOP
tText := rRecord.count;
RAISE NOTICE 'Notice %',tText ;
END LOOP ;
END;
$$
LANGUAGE plpgsql ;
I am trying create this script where if it matches the current database , then do a chunk of work inside a sub block. As this is my first attempt, i cannot get this to work. Any thoughts?
DO
$do$
DECLARE
database CONSTANT text[] := array['prd1', 'prd2'];
BEGIN
IF current_database() = any(database)
THEN
**--execute the below sub block**
DECLARE
v_sql text;
BEGIN
v_sql :=
IF NOT EXISTS (
SELECT FROM pg_catalog.pg_roles -- SELECT list can be empty for this
WHERE rolname = 'dave') THEN
create role dave encrypted password 'md502bbddbc560b6470b360219ac95c13e2';
create schema authorization dave;
END IF;
END
);
-- end of sub block
END IF;
END
$do$;
SQL Error [42601]: ERROR: syntax error at or near "NOT" Position:
231
What i want do is a like where it does alot of actions in a sub block:
DO
$do$
DECLARE
database CONSTANT text[] := array['prd1', 'prd2'];
BEGIN
IF current_database() = any(database)
THEN
**--execute the below sub block**
DECLARE
v_sql text;
BEGIN
v_sql :=
IF NOT EXISTS (
SELECT FROM pg_catalog.pg_roles -- SELECT list can be empty for this
WHERE rolname = 'dave') THEN
create role dave encrypted password 'md502bbddbc560b6470b360219ac95c13e2';
create schema authorization dave;
END IF;
END
do
$$
begin
execute format('grant connect, temporary on database %I to %I', current_database(), 'user_monitor');
end;
$$;
CREATE OR REPLACE FUNCTION test.log_ddl()
RETURNS event_trigger AS $$
DECLARE
audit_query TEXT;
r RECORD;
BEGIN
[...]
END;
$$ LANGUAGE plpgsql;
**-- end of sub block**
END IF;
END
$do$;
Why use sub-block when you can use the IF conditional? 2) Why v_sql := ...? I see no point in assigning the query to a variable. Again all you want is to take CREATE actions based on the IF condition. –
Adrian Klaver
I have a stored procedure(P1) that returns a refcursor and few other text datatype values.
I have another procedure(P2) where I need to the fetch P1's refcursor output and insert it into a temporary table. The temporary table has matching columns and datatypes.
create or replace procedure P1(inout rfcur refcursor, in dtl text)
as
$$
begin
open rfcur for select * from tst_dump where ident = dtl;
end;
$$
language plpgsql;
create or replace P2(inout rfc refcursor, in dt_array text[])
as
$$
declare
i record;
cur refcursor;
begin
for i in array_lower(dt_array, 1)..array_upper(dt_array, 1) loop
call P1(cur, i);
--I need to fetch the result set from `cur` and store into a temp table `t_tab1`.
end loop;
end;
$$
language plpgsql;
Is it possible to achieve this in Postgres?
NOTE: I'm not supposed to make any changes to the procedure P1.
p2 could look like this:
CREATE PROCEDURE p2(IN dt_array text[])
LANGUAGE plpgsql AS
$$DECLARE
r record;
i integer;
cur refcursor;
BEGIN
FOR i IN array_lower(dt_array, 1)..array_upper(dt_array, 1) LOOP
CALL p1(cur, i::text);
LOOP
FETCH cur INTO r;
EXIT WHEN NOT FOUND;
INSERT INTO t_tab1 (...) VALUES (r.col1, r.col2, ...;
END LOOP;
END LOOP;
END;$$;
You should indent your code. That's the basic requirement when you program.
It seems to me that you are doing something the wrong way. Using procedures and cursors complicates everything and makes it slower.
You should do something like
INSERT INTO t_tab
SELECT /* your original query */;
After reading the documentation for ASSERT, I am still confused how to use it, and can't find any examples online of how I would do something simple using ASSERT in a .sql script.
For example, say I want to ASSERT that the number of rows returned from SELECT * FROM my_table WHERE my_col = 3 is equal to 10.
Can someone provide a working example of that?
I would assume you try todo smth similar?
so=# select count(*) from pg_database;
count
-------
21
(1 row)
so=# do $$ begin assert (select count(*) from pg_database) = 21, 'not 21!';end;$$;
DO
so=# do $$ begin assert (select count(*) from pg_database) = 22, 'not 22!';end;$$;
ERROR: not 22!
CONTEXT: PL/pgSQL function inline_code_block line 1 at ASSERT
do $$
begin
ASSERT 1 = 2;
end;
$$ LANGUAGE plpgsql;
But note, it works only starting from PostgreSql 9.5. In older versions you can define your own assert-function such like this
CREATE OR REPLACE FUNCTION __assert(boolean) RETURNS VOID AS $$
BEGIN
IF NOT $1 THEN
RAISE EXCEPTION 'ASSERTING FAILED';
END IF;
END;
$$ LANGUAGE plpgsql;
And then use in this way
do $$
declare
tmp char;
begin
tmp := __assert(tmp_to_https('https') = 'https');
end;
$$ LANGUAGE plpgsql;
do
$xyz$
declare
y text;
i record;
begin
y := to_char(current_timestamp, 'YYYYMMDDHHMMSS');
raise notice '%',y;
execute 'CREATE TEMP TABLE someNewTable'
||y
||' AS select * from ( VALUES(0::int,-99999::numeric), (1::int, 100::numeric)) as t (key, value)';
for i in (select * from someNewTable||y) loop
raise notice '%',i.key;
end loop;
end;
$xyz$ language 'plpgsql'
ERROR: syntax error at or near "||"
LINE 13: for i in (select * from someNewTable||y) loop
Im unable to understand why the error is at the PIPE symbol. Please help me. I have been trying in Oracle db too, but same error. Am I doing anything wrong here?
The query in for ... loop statement also has to be dynamic, so you should use execute twice.
Use the format() function which is very convenient in conjunction with execute:
do $xyz$
declare
y text;
i record;
begin
y := to_char(current_timestamp, 'YYYYMMDDHHMMSS');
raise notice '%', y;
execute format($ex$
create temp table somenewtable%s
as select * from (
values
(0::int, -99999::numeric),
(1::int, 100::numeric)
) as t (key, value)
$ex$, y);
for i in
execute format($ex$
select * from somenewtable%s
$ex$, y)
loop
raise notice '%',i.key;
end loop;
end;
$xyz$ language 'plpgsql';