I'm using django-tenants, and for some tests I need to delete all schemas at once, so I was wondering how could I delete all schemas with a single sentence/script from postgresql shell, because deleting one by one is not scalable.
Thx so much.
For deleting all schemas you must use dynamic SQL. And schema names you can get from statistic system tables (example: information_schema). Example Query:
do
$body$
declare
f_rec record;
begin
for f_rec in
SELECT schema_name::text
FROM information_schema.schemata
where schema_name <> 'public'
loop
execute 'DROP SCHEMA ' || f_rec.schema_name || ' CASCADE';
end loop;
end;
$body$
language 'plpgsql';
Related
I have one database with multiple schemas. I would like to run SELECT * FROM info, across all schemas that starts with "team".
The schemas are not fixed, meaning that schemas are added and dropped continuously, so I can't hardcode the schemas in the query. But I'm only interested in schemas that starts with "team". How do I do this?
If all tables have an identical structure, you can write a PL/pgSQL function that does this:
create function get_info(p_schema_prefix text)
returns table (... column definitions go here ...)
as
$$
declare
l_rec record;
l_sql text;
begin
for l_rec in select table_schema, table_name
from information_schema.tables
where table_name = 'info'
and table_schema like p_schema_prefix||'%'
loop
l_sql := format('select id, data from %I.%I', l_rec.table_schema, l_rec.table_name);
return query execute l_sql;
end loop;
end;
$$
language plpgsql;
The use it like this:
select *
from get_info('team')
We have multiple schemas, I would like to run a simple count query across schemas such as:
SELECT COUNT(col_x) FROM schema1.table WHENRE col_x IS NOT NULL
I saw that I'm able to get all the schemas with:
SELECT schema_name FROM information_schema.schemata
So by using:
set search_path to schema1;
SELECT COUNT(col_x)
FROM table
WHERE col_x is not NULL;
I was able to run the query for schema1
The question is - is it possible to run in a loop and use the schema name as a parameter for search_path and run the query across all schemas? or any other efficient way to do so?
You will need some plpgsql and dynamic SQL for this. Here is an anonymous block for illustration:
do language plpgsql
$$
declare
v_schema_name text;
table_row_count bigint;
sysSchema text[] := array['pg_toast','pg_temp_1','pg_toast_temp_1','pg_catalog','public','information_schema'];
-- other declarations here
begin
for v_schema_name in SELECT schema_name FROM information_schema.schemata WHERE (schema_name != ALL(sysSchema)) loop
begin
execute format('select count(col_x) from %I.t_table', v_schema_name)
into table_row_count;
raise notice 'Schema % count %', v_schema_name, table_row_count;
exception when others then null; -- t_table may not exists in some schemata
end;
-- other statements here
end loop;
end;
$$;
And btw WHERE col_x is not NULL is redundant.
I am looking to automate each table update with an automatic update of the updated_at column. I am able to make this work for a specific table using a trigger. But my main goal, which I can't find anywhere, is to create a function that dynamically grabs all the tables in the schema, and creates that same trigger and only changing the table name that the trigger is referencing to. For the life of me I can't figure it out.
I believe this shouldn't be as tricky as I'm making it as ever table in our schema will have the exact same column name of 'updated_at'.
One solution that I tried and thought would work was turning the table schema into an array, and iterating through that to invoke/create the trigger each iteration. But I don't have a ton of psql experience so I am finding myself googling for hours to solve this one little thing.
SELECT ARRAY (
SELECT
table_name::text
FROM
information_schema.tables
WHERE table_schema = 'public') as tables;
I have also tried:
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 update_updatedAt
BEFORE UPDATE ON %I
FOR EACH ROW EXECUTE PROCEDURE updated_at()',
t);
END loop;
END;
$$ language 'plpgsql';
Procedure:
CREATE OR REPLACE FUNCTION updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
Your DO block works. The only problem with it is we can't have same Trigger name for multiple triggers. So, you can either add a table_name suffix/prefix for the Trigger name.
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 update_updatedAt_%I
BEFORE UPDATE ON %I
FOR EACH ROW EXECUTE PROCEDURE updated_at()',
t,t);
END loop;
END;
$$ language 'plpgsql';
Additionally you may add a check to see if the trigger already exists in information_schema.triggers to be safe.
IF NOT EXISTS ( SELECT 1 from information_schema.triggers
where trigger_name = 'update_updatedat_'|| t)
THEN
I found many such questions but the answers where all using Stored Procedures.
I want an answer that uses purely a query in Oracle Sql Developer.
I have a value 'CORE_AO0001031_70_EMail_1' but not sure in which table. The number of tables and the data inside them are very huge.
Doesn't matter if the query is huge and will take time to execute. Is there any such query?
The reason for my asking a query is, I don't have privilege to create a Stored Procedure and I won't be given that privilege. Please help me with a query.
With an SQL you can't, as the queries are going to be dynamic. You have to execute a PL/SQL atleast.
Note: This is a Costly operation!
You can still attempt a full download of all you tables as spooling, and make PERL search into all files. In that case, you need a lot of disk space, but less harm(Just better than the Pl/SQL) to the database
DECLARE
TYPE TY_TABLE_NAMES IS TABLE OF VARCHAR2(30);
L_TABLE_NAMES TY_TABLE_NAMES;
TYPE TY_COLUMN_NAMES IS TABLE OF VARCHAR2(30);
L_COLUMN_NAMES TY_COLUMN_NAMES;
v_SCHEMA_NAME VARCHAR2(30) = 'SYSTEM'; --Your Schema Name
v_QUERY_STRING VARCHAR2(4000);
v_SEARCH_STRING VARCHAR2(4000) := 'CORE_AO0001031_70_EMail_1';
v_SEARCH_FLAG CHAR(1) := 'N';
BEGIN
SELECT ALL_TABLES
BULK COLLECT INTO L_TABLE_NAMES
WHERE OWNER = v_SCHEMA_NAME;
FOR I In 1..L_TABLE_NAMES.COUNT LOOP
SELECT COLUMN_NAME
BULK COLLECT INTO L_COLUMN_NAMES
FROM ALL_TAB_COLUMNS
WHERE TBALE_NAME = L_TABLE_NAMES(I)
AND OWNER = v_SCHEMA_NAME;
FOR J In 1..L_COLUMN_NAMES.COUNT LOOP
BEGIN
v_QUERY_STRING := 'SELECT ''Y'' FROM DUAL WHERE EXISTS (SELECT ''X'' FROM '||L_TABLE_NAMES(I)||' WHERE '||
||L_COLUMN_NAMES(J)|| ' LIKE ''%'|| v_SEARCH_STRING||'%'')';
EXCECUTE IMMEDIATE v_QUERY_STRING INTO v_SEARCH_FLAG;
WHEN NO_DATA_FOUND THEN
v_SEARCH_FLAG := 'N';
END;
IF(v_SEARCH_FLAG = 'Y') THEN
DBMS_OUTPUT.PUT_LINE(v_SEARCH_STRING || ' found in column '||L_COLUMN_NAMES(I)|| ' of table '||L_TABLE_NAMES(I));
BREAK;
END IF;
END LOOP;
IF(v_SEARCH_FLAG = 'Y') THEN
DBMS_OUTPUT.PUT_LINE('Done Searching!');
BREAK;
END IF;
END LOOP;
END;
/
I want to drop certain tables in a tablespace that has common name appended to end of each table for an example:
TABLE1_NAME1_COMMON
TABLE2_NAME2_COMMON
TABLE3_NAME3_COMMON
I heard about Oracle functions but I'm not familiar much with those so I'm expecting some helping hand.
Thanks.
If you're completely sure what you're doing, ie, if you're sure that you don't accidentally drop a table that you don't want to drop, you can do a:
set serveroutput on size 1000000
begin
for r in (
select table_name
from user_tables
where table_name like '%\_COMMON' escape '\')
loop
execute immediate 'drop table ' || r.table_name;
end loop;
exception when others then
dbms_output.put_line(sqlerrm);
end;
/
Edit:
Changed Now selecting from user_tables instead of dba_tables as it seems more safe to do.
Added set serveroutput on in order for dbms_output.put_line to be printed
Added begin .. exception .. end in order for errors to be shown.
You could do that in a procedure, but it might be better to just select those DROP-statements, review them and execute them manually:
SELECT 'DROP TABLE ' || table_name || ';'
FROM user_tables
WHERE table_name LIKE '%\_COMMON' ESCAPE '\';
would return
DROP TABLE TABLE1_NAME1_COMMON;
DROP TABLE TABLE2_NAME2_COMMON;
DROP TABLE TABLE3_NAME3_COMMON;
to identify them you can use:
SELECT * FROM user_tables WHERE tablespace_name='MySpace' AND table_name like '%COMMON';
You could then either, derive your DROP statements using a SELECT. Or you could write a PL/SQL function to loop through the "Common Tables" and DROP them using EXECUTE IMMEDIATE.
I would make sure you are 100% sure in the selections first however.