create table x(y number, z character varying(100))
insert into x values (1,'foo');
insert into x values (2,'bar');
do $$
declare
k character varying(100);
begin
EXECUTE 'SELECT z FROM '
||quote_ident(x)
into k;
RAISE NOTICE '%',k;
end;
$$ language 'plpgsql';
ERROR: column "x" does not exist
LINE 2: ||quote_ident(x)
^
QUERY: SELECT 'SELECT z FROM '
||quote_ident(x)
CONTEXT: PL/pgSQL function inline_code_block line 7 at
EXECUTE
SQL state: 42703
May I know what am I doing wrong here and I'm on 9.5. Even EXECUTE format is also giving me the same error.
do $$
declare
k character varying(100);
begin
EXECUTE 'SELECT z FROM '
||quote_ident('x')
into k;
RAISE NOTICE '%',k;
end;
$$ language 'plpgsql';
quotes around 'x' worked for me. Thanks
Related
I want to create a stored procedure in pgadmin that will output the number of rows from the "Trip" table. The table itself is output in cmd, the number of rows in this table is also output in cmd. But when writing a procedure and calling it, such an error comes out. I have psql version 15. How can I fix this error?
My code:
CREATE PROCEDURE example2(INOUT _name character varying) AS $$
BEGIN
SELECT count(*) FROM "_name";
END;
$$ LANGUAGE plpgsql;
CALL example2(Trip)
Error:
ERROR: ERROR: The "trip" column does not exist
LINE 7: CALL example2(Trip)
You are better off using a function then a procedure as it is easier to get value out. Using dynamic SQL along with the format function to properly quote the _name parameter.
CREATE OR REPLACE FUNCTION public.example2(_name character varying)
RETURNS integer
LANGUAGE plpgsql
AS $function$
DECLARE
ct integer;
BEGIN
EXECUTE format('SELECT count(*) FROM %I', _name) INTO ct;
RETURN ct;
END;
$function$
select example2('animals');
example2
----------
8
I am new to postgres. I need to create a function that will take a list of all the tables in the database whose names are stored in one table and then delete the records of all the tables that are older than x days and have a certain row_status. Some tables do not have a row_status column.
I get an error when I try to save a written function in dbeaver -> ERROR: syntax error at or near "||"
create function delete_old_records1(day1 int, row_status1 character default null, row_status2 character default null)
returns void
language plpgsql
as $$
declare
c all_tables1%rowtype;
begin
for c in select * from all_tables1 loop
if exists(SELECT column_name FROM information_schema.columns
WHERE table_schema = 'yard_kondor' AND table_name =c.table_name AND column_name = 'row_status') then
execute 'delete from '||c.table_name||' where row_create_datetime>current_date-day1+1 and
row_status in (coalesce(row_status1,''P''), row_status2)';
else
execute 'delete from '||c.table_name||' where row_create_datetime>current_date-day1+1';
raise notice 'Table '||c.table_name||' does not have row_status column';
end if;
end loop;
return;
commit;
end;
$$
Your immediate problem is this line:
raise notice 'Table '||c.table_name||' does not have row_status column';
That should be:
raise notice 'Table % does not have row_status column', c.table_name;
However, your function could be improved a bit. In general it is highly recommended to use format() to generate dynamic SQL to properly deal with identifiers. You also can't commit in a function. If you really need that, use a procedure.
create function delete_old_records1(day1 int, row_status1 character default null, row_status2 character default null)
returns void
language plpgsql
as $$
declare
c all_tables1%rowtype;
begin
for c in select * from all_tables1
loop
if exists (SELECT column_name FROM information_schema.columns
WHERE table_schema = 'yard_kondor'
AND table_name = c.table_name
AND column_name = 'row_status') then
execute format('delete from %I
where row_create_datetime > current_date - %J + 1
and row_status in (coalesce(row_status1,%L), row_status2)', c.table_name, day1, 'P');
else
execute format('delete from %I where row_create_datetime > current_date - day1 + 1', c.table_name);
raise notice 'Table % does not have row_status column', c.table_name;
end if;
end loop;
return;
-- you can't commit in a function
end;
$$
Thank you for answer. Now I'm able to save function, but currently I have a problem with running the function.
I started the function with:
DO $$ BEGIN
PERFORM "delete_old_records1"(31,'P','N');
END $$;
I started script with ALT+X (also tried select delete_old_records1(31,'P','N');) and have this error:
SQL Error [42703]: ERROR: column "day1" does not exist
Where: PL/pgSQL function delete_old_records1(integer,character,character) line 11 at EXECUTE statement
SQL statement "SELECT "delete_old_records1"(31,'P','N')"
PL/pgSQL function inline_code_block line 2 at PERFORM
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';
I am getting an error for the below FOR loop with cursor in a function:
ERROR: syntax error at or near "AS"
CREATE OR REPLACE FUNCTION functionName(custom varchar(15)) RETURNS INTEGER AS $$
DECLARE
...
BEGIN
...
FOR loop AS cursor CURSOR FOR
SELECT column FROM table
DO
...
END FOR;
RETURN someValue;
END;
$$
LANGUAGE plpgsql;
This is wrong syntax - Postgres doesn't support declaration of CURSOR inside FOR statement. See documentation:
CREATE OR REPLACE FUNCTION foo()
RETURNS void AS $$
DECLARE r record;
BEGIN
FOR r IN SELECT xx,yy FROM some_tab
LOOP
RAISE NOTICE 'row data: %', r;
END LOOP;
END;
$$ LANGUAGE plpgsql;
It looks so you are using ANSI SQL PSM syntax. PL/pgSQL is based on PL/SQL syntax (Oracle/ADA).
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.