[42601][500310] [Amazon](500310) Invalid operation: syntax error at or near "$1"; - amazon-redshift

CREATE or REPLACE PROCEDURE admin.sp_pm_drop_all_scratch_tables (redshift_table_name IN VARCHAR)
LANGUAGE plpgsql
as $$
DECLARE
temp_table_name varchar(100);
row record;
BEGIN
temp_table_name := 'procedure_temp_table';
EXECUTE 'DROP TABLE if exists '||temp_table_name;
EXECUTE 'CREATE TEMP TABLE '||temp_table_name||' as select * from nidhi_test.'||redshift_table_name;
FOR row IN(
select 'DROP TABLE IF EXISTS '|| schemaname || '."'|| tablename|| '" cascade' as sql_name
from pg_tables
where schemaname in ('nidhi_scratch')
and schemaname || '.'|| tablename not in (select schema_name || '.'|| table_name from temp_table_name)
)
LOOP
EXECUTE row.sql_name;
END LOOP;
end;
$$ ;
i am trying to create this procedure but getting this error[42601][500310] Amazon Invalid operation: syntax error at or near "$1";
when i try to run this procedure it gives me the error
[42601][500310] Amazon Invalid operation: syntax error at or near "$1";
basically i want to drop the tables from schema nidhi_scratch and not drop tables which are there in temp_table_name
temp_table_name is getting filled from nidhi_test.‘||redshift_table_name
redshift_table_name is a variable getting filled from airflow

Related

ERROR: column "file_name" does not exist LINE 1: SELECT distinct(file_name) , uploaded_date, .. Postgresql dynamic sub query

create or replace function get_value2(tbl varchar, tbl1 anyelement) RETURNS
refcursor AS
$$
declare
ref_cursor REFCURSOR;
--refcursor declaration
begin
OPEN ref_cursor FOR EXECUTE
'SELECT distinct(file_name) , uploaded_date, ' ||'(SELECT STRING_AGG(column_name, ',')
from information_schema.columns
where table_name =' || quote_literal(tbl) ')' ||
'FROM ' || pg_typeof(tbl1); --table name from parameter
RETURN (ref_cursor);
end;
$$ LANGUAGE plpgsql;
--pg_typeof(tbl1) table name from parameter
any help will be appreciated

Postgres - Use table name (passed in parameter) in function body

I am a newbie wrt functions and I am struggling with using the name of a table in the function body. I get an error "SQL Error [42703]: ERROR: column "tname" does not exist" when I call the function using
select "JsonToView"('data_import.import_360xero_report');
My code is below
create or replace
function data_import."JsonToView"(tname text) returns numeric
language plpgsql
as $function$
begin
do
$$
declare
l_keys text;
begin
drop view if exists v_json_view cascade;
select
string_agg(distinct format('import_data ->> %L as %I', jkey, jkey), ', ')
into
l_keys
from
import_360xero_report,
json_object_keys(import_data) as t(jkey);
execute 'create view v_json_view as select ' || l_keys || ' from ' || tname;
end;
$$;
return 0;
end $function$ ;
I have modified the code and the second create view query works with the table name but the first one does not.
Below if my modified code
create or replace
function data_import."JsonToView"(tname text) returns numeric
language plpgsql
as $function$
declare
l_keys text;
begin
drop view if exists v_json_view cascade;
execute $a$select
string_agg(distinct format('import_data ->> %L as %I', jkey, jkey), ', ')
into
l_keys
from $a$ ||
tname || $b$,
json_object_keys(import_data) as t(jkey)$b$;
execute 'create view v_json_view as select ' || l_keys || ' from ' || tname;
return 0;
end $function$ ;
The error I am getting is
SQL Error [0A000]: ERROR: EXECUTE of SELECT ... INTO is not implemented
Hint: You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.
Where: PL/pgSQL function "JsonToView"(text) line 10 at EXECUTE
The problem is the superfluous nested DO statement.
The variable tname exists only in the scope of the function, not in the nested DO statement. DO is an SQL statement, not a PL/pgSQL statement, and there are no variables in SQL. Also, DO does not allow parameters.
Get rid of the DO and you will be fine.

Returning table name becomes string

Hello I got 500 tables in public and I try to create triggers for all tables ,by first finding all table names and creating a trigger if not already exists here is the code:
CREATE OR REPLACE FUNCTION get_all_results() RETURNS VOID AS
$BODY$
DECLARE
r RECORD;
BEGIN
IF (SELECT "session_user"() <> 'asdf' THEN
FOR r IN (SELECT 'CREATE TRIGGER ' || tab_name|| '_if_modified_trg AFTER INSERT OR UPDATE OR DELETE ON ' || tab_name|| ' FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ' AS trigger_creation_query
FROM (
SELECT quote_ident(table_name) as tab_name
FROM information_schema.tables
WHERE table_schema='public'
AND table_type != 'VIEW'
) AS foo WHERE tab_name||'_if_modified_trg' NOT IN (SELECT tgname from pg_trigger where not tgisinternal))
LOOP
-- can do some processing here
EXECUTE r.trigger_creation_query;
END LOOP;
RETURN;
END IF;
END
$BODY$
LANGUAGE plpgsql;
SELECT * FROM get_all_results();
and I get this error :
ERROR: syntax error at or near "_if_modified_trg"
LINE 1: CREATE TRIGGER "position"_if_modified_trg AFTER INSERT OR UP...
I really have table position in one of these 500 and the name is position not "position".

SELECTing commands into a temp table to EXECUTE later in PostgreSQL

For some fancy database maintenance for my developer database I'd like to be able to use queries to generate commands to alter the database. The thing is: I'm a complete greenhorn to PostgreSQL. I've made my attempt but have failed colorfully.
So in the end, I would like to have a table with a single column and each row would be a command (or group of commands, depending on the case) that I would think would look something like this...
DO $$
DECLARE
command_entry RECORD;
BEGIN
FOR command_entry IN SELECT * FROM list_of_commands
LOOP
EXECUTE command_entry;
END LOOP;
END;
$$;
Where the table list_of_commands could be populated with something like the following (which in this example would remove all tables from the public schema)...
CREATE TEMP TABLE list_of_commands AS
SELECT 'drop table if exists "' || tablename || '" cascade;'
FROM pg_tables
WHERE schemaname = 'public';
However, with this I get the following error...
ERROR: syntax error at or near ""drop table if exists ""dummy_table"" cascade;""
LINE 1: ("drop table if exists ""dummy_table"" cascade;")
I assume this is a matter of escaping characters, but I'm not entirely sure how to fit that into either A) the population of the table or B) the execution of each row. Does anyone know what I could do to achieve the desired result?
The command_entry variable is of type record while the EXECUTE command expects a string. What is apparently happening is that PostgreSQL turns the record into a double-quoted string, but that messes up your command. Also, your temp table does not use a column name, making things a bit awkward to work with (the column name becomes ?column?), so change both as follows:
CREATE TEMP TABLE list_of_commands AS
SELECT 'drop table if exists public.' || quote_ident(tablename) || ' cascade' AS cmd
FROM pg_tables
WHERE schemaname = 'public';
DO $$
DECLARE
command_entry varchar;
BEGIN
FOR command_entry IN SELECT cmd FROM list_of_commands
LOOP
EXECUTE command_entry;
END LOOP;
END;
$$;
But seeing that you do all of this at session level (temp table, anonymous code block), why not write a stored procedure that performs all of this housekeeping when you are ready to do spring cleaning?
CREATE FUNCTION cleanup() RETURNS void AS $$
BEGIN
FOR tbl IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
LOOP
EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(tbl) || ' CASCADE';
END LOOP;
-- More housekeeping jobs
END;
$$ LANGUAGE plpgsql;
This saves a lot of typing: SELECT cleanup();. Any other housekeeping jobs you have you simply add to the stored procedure.
I had trouble with Patrick's answers, so here is an updated version for postgreSQL 10.
CREATE FUNCTION droptables(sn varchar) RETURNS void AS $$
DECLARE
tbl varchar;
BEGIN
FOR tbl IN SELECT tablename FROM pg_tables WHERE schemaname = sn
LOOP
EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(tbl) || ' CASCADE';
END LOOP;
END;
$$ LANGUAGE plpgsql;
And then "SELECT droptables('public');".

How to change schema of multiple PostgreSQL tables in one operation?

I have a PostgreSQL 9.1 database with 100 or so tables that were loaded into the 'public' schema. I would like to move those tables (but not all of the functions in 'public') to a 'data' schema.
I know that I can use the following to move 1 table at a time.
ALTER TABLE [tablename] SET SCHEMA [new_schema]
Is it possible to move all of the tables to the new schema in one operation? If so, what would be the most efficient way to accomplish this task?
DO will do the trick:
DO
$$
DECLARE
row record;
BEGIN
FOR row IN SELECT tablename FROM pg_tables WHERE schemaname = 'public' -- and other conditions, if needed
LOOP
EXECUTE format('ALTER TABLE public.%I SET SCHEMA [new_schema];', row.tablename);
END LOOP;
END;
$$;
-- ####### USING DBEAVER WHICH SUPPORT VARIABLES ########
-- ### ANSWER_1 -- USING DO ###--------
-- Step1: Set variables one by one
#set _SCHEMA = 'public'
#set _COLUMN = 'dml_status'
#set _DATA_TYPE = 'integer'
#set _DEFAULT = '1'
-- Step2: Call the below procedure
DO
$$
DECLARE
row record;
query varchar;
BEGIN
FOR ROW IN SELECT table_name FROM information_schema.tables WHERE table_schema = ${_SCHEMA}
LOOP
query :='ALTER TABLE public.' || quote_ident(row.table_name) ||' ADD COLUMN IF NOT EXISTS '||${_COLUMN} || ' ' || ${_DATA_TYPE} ||' not null default ' || ${_DEFAULT} || ';' ;
execute query;
END LOOP;
END;
$$;
-- ### ANSWER_2 -- STORE PROCEDURE FN ###--------
DROP FUNCTION addColumnToMultipleTables cascade;
create or replace function addColumnToMultipleTables()
returns void
LANGUAGE 'plpgsql'
as $$
DECLARE
row record;
query varchar;
BEGIN
FOR ROW IN SELECT table_name FROM information_schema.tables WHERE table_schema = ${_SCHEMA}
LOOP
query :='ALTER TABLE public.' || quote_ident(row.table_name) ||' ADD COLUMN IF NOT EXISTS '||${_COLUMN} || ' ' || ${_DATA_TYPE} ||' not null default ' || ${_DEFAULT} || ';' ;
raise info 'query : % ', query;
execute query;
END LOOP;
END;
$$;
select addColumnToMultipleTables();