Simple PostgreSQL plpgsql to create a new table using existing table - postgresql

I'm new to plpgsql. I'm sure there is some really simple way to do this, but for some reason I'm having a lot of trouble trying to figure out how to do this.
I'm simply trying to loop through the list of existing tables and execute
CREATE TABLE z_existing_table_name AS SELECT * FROM existing_table_name WITH DATA
So far, I have this:
CREATE OR REPLACE FUNCTION create_backup_row()
RETURNS RECORD
AS $$
DECLARE
row RECORD;
BEGIN
FOR row IN SELECT * FROM information_schema.tables WHERE table_catalog = 'my_db' and table_schema = 'public'
LOOP
EXECUTE 'CREATE TABLE z_' || t.table_name || ' as ' || t.table_name
END LOOP;
END;
$$ LANGUAGE plpgsql;
It would be an added bonus if I can make this function re-runnable. Something like drop table if exist then create table ...

#Steven, use below procedure,
-- Function: create_backup_row()
-- DROP FUNCTION create_backup_row();
CREATE OR REPLACE FUNCTION create_backup_row()
RETURNS integer AS
$BODY$
DECLARE
v_table text;
BEGIN
FOR v_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_catalog = 'my_db'
AND table_schema = 'public'
AND table_name not ilike '%z_%' -- to skip the table with z_ when we rerun it.
LOOP
EXECUTE ' DROP TABLE IF EXISTS z_' || v_table ;
EXECUTE 'CREATE TABLE z_' || v_table || ' as SELECT * FROM ' || v_table ;
END LOOP;
return 1;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION create_backup_row()
OWNER TO postgres;

Related

How to execute query statements generated in pgAdmin4?

I have the following query which generates a list of ALTER TABLE statements in the 'Data Output' field in pgAdmin4. I can copy & paste them back into the query pane and execute them there.
select 'ALTER TABLE ' || table_name || ' OWNER TO myuser;' from information_schema.tables where table_schema = 'public';
How can I execute the generated statements without having to copy & paste them?
You can use the function for that.
CREATE OR REPLACE FUNCTION change_permission_table()
RETURNS VOID AS $$
DECLARE
rec text;
BEGIN
FOR rec IN SELECT 'ALTER TABLE ' || table_name || ' OWNER TO maz;' FROM information_schema.tables WHERE table_schema = 'public'
LOOP
EXECUTE rec;
END LOOP;
END;
$$ LANGUAGE plpgsql;
-- Run the function to change the permission
SELECT change_permission_table()

Postgresql, how to add multiple table for one trigger

I have a question: how to add multiple table for one trigger?
Is that possible, or should I just make another 2 triggers for 2 different tables?
Create a new function
CREATE OR REPLACE FUNCTION updated_timestamp_func()
RETURNS TRIGGER
LANGUAGE plpgsql AS
'
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
';
Then create a trigger for each table that has the column updated_at
DO $$
DECLARE
t text;
BEGIN
FOR t IN
SELECT table_name FROM information_schema.columns WHERE column_name = 'updated_at'
LOOP
EXECUTE format('CREATE TRIGGER trigger_update_timestamp
BEFORE UPDATE ON %I
FOR EACH ROW EXECUTE PROCEDURE updated_timestamp_func()', t,t);
END loop;
END;
$$ language 'plpgsql';
Iterate one trigger for all tables
(For Example Foreign Tables)
DO
$$
DECLARE
r RECORD;
BEGIN
FOR r IN SELECT *
FROM information_schema.tables
where table_type = 'FOREIGN TABLE'
and table_schema = 'public'
and table_name <> 'django_migrations'
LOOP
RAISE NOTICE 'CREATE TRIGGER FOR: %', r.table_name::text;
EXECUTE 'CREATE TRIGGER trg_insert_ids
BEFORE INSERT
on ' || r.table_name || ' FOR EACH ROW
EXECUTE PROCEDURE insert_ids();';
END LOOP;
END;
$$ LANGUAGE plpgsql;
You need to define a trigger for each table, so if you have two tables, you need two triggers.
However, multiple triggers can use the same trigger function.

Loop through all user tables and insert row in each

for some reason I just can not figure this out. I have a seperate schema in PostgreSQL for notification related tables for each user connected to the server. My plan is to have each user create a TEMP table to receive extra notification info from since Xojo doesn't support PostgreSQL payloads.
I feel like I'm starting to get close so I'll just post my code that is in my trigger function.
DECLARE
my_table RECORD;
BEGIN
FOR my_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'information_schema'
LOOP
INSERT INTO my_table.table_name (effected_row_id)
VALUES (NEW.effected_row_id);
END LOOP;
END;
Tell me if I'm wrong, but I believe my main problem is figuring out how to use the table name returned from the SELECT statement in the INSERT statement.
EDIT:
This is my current trigger function
-- Function: notification.my_insert_trigger_function()
-- DROP FUNCTION notification.my_insert_trigger_function();
CREATE OR REPLACE FUNCTION notification.my_insert_trigger_function()
RETURNS trigger AS
$BODY$DECLARE
my_table RECORD;
BEGIN
FOR my_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'notification' AND table_name <> 'notification_global' AND table_name <> 'switcher'
LOOP
EXECUTE(FORMAT($f$
INSERT INTO %s (effected_row_username)
VALUES (%s);
$f$, 'notification.' || my_table.table_name, NEW.effected_row_username));
END LOOP;
RETURN new;
END;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION notification.my_insert_trigger_function()
OWNER TO serveradmin;
You need to use dynamic commands in your trigger function.
The funcion format() is often very helpful.
DECLARE
my_table RECORD;
BEGIN
FOR my_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'information_schema'
LOOP
EXECUTE(FORMAT($f$
INSERT INTO %s (effected_row_id)
VALUES (%s);
$f$, my_table.tablename, NEW.effected_row_id));
END LOOP;
END;

In postgres how can I delete all columns that share the same prefix

I have been using the following code for dropping all tables that share the same prefix (in this case delete all tables that their name starts with 'supenh_'):
DO
$do$
DECLARE
_tbl text;
BEGIN
FOR _tbl IN
SELECT quote_ident(table_schema) || '.'
|| quote_ident(table_name) -- escape identifier and schema-qualify!
FROM information_schema.tables
WHERE table_name LIKE 'supenh_' || '%' -- your table name prefix
AND table_schema NOT LIKE 'pg_%' -- exclude system schemas
LOOP
-- RAISE NOTICE '%',
EXECUTE
'DROP TABLE ' || _tbl;
END LOOP;
END
$do$;
Is there a way to amend this code / or to use a different script in order to delete from one specific table all the columns that start with the same prefix (for example, 'patient1_') ?
You could write it as PL/pgSQL function:
CREATE OR REPLACE FUNCTION drop_columns_with_prefix(tbl_name TEXT, column_prefix TEXT) RETURNS VOID AS
$BODY$
DECLARE
_column TEXT;
BEGIN
FOR _column IN
SELECT quote_ident(column_name)
FROM information_schema.columns
WHERE table_name = tbl_name
AND column_name LIKE column_prefix || '%'
AND table_schema NOT LIKE 'pg_%'
LOOP
-- RAISE NOTICE '%',
EXECUTE
'ALTER TABLE ' || tbl_name || ' DROP COLUMN ' || _column;
END LOOP;
END
$BODY$
LANGUAGE plpgsql VOLATILE;
Call it using:
SELECT drop_columns_with_prefix('tbl_name', 'prefix_');
Or if you don't want to use it as a function:
DO
$do$
DECLARE
_column TEXT;
BEGIN
FOR _column IN
SELECT quote_ident(column_name)
FROM information_schema.columns
WHERE table_name = 'tbl_name'
AND column_name LIKE 'prefix_%'
AND table_schema NOT LIKE 'pg_%'
LOOP
-- RAISE NOTICE '%',
EXECUTE
'ALTER TABLE tbl_name DROP COLUMN ' || _column;
END LOOP;
END
$do$

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();