How can I delete all tables from a Firebird 3.0 database using single query? - firebird

I'm working on JSF application that uses a Firebird 3.0 database containing hundreds of tables. I need to delete all tables time to time.
I have checked this query:
DROP TABLE TABLE_NAME
but only one table can be deleted at a time by using this query and its very time consuming for program, can I have another approach to hammer it away?

You can create procedure in which drop tables
create or alter procedure PRC_DROP_TABLES
as
declare variable TBL varchar(50);
begin
for select r.rdb$relation_name
from rdb$relation_fields r
where
r.rdb$system_flag=0 and r.rdb$view_context is null
-- and r.rdb$relation_name not containing '$' --uncomment and modify this if you what filter tables by condition
group by r.rdb$relation_name
into :tbl do
execute statement 'drop table '||:tbl;
end

Related

Is there any way to list all the views related to a table in the existing postgres schema

I got a Postgres database with multiple schemas. I'm trying to optimise my database tables with optimal data types. more often I end with the error
cannot alter the type of a column used by a view
while using the query alter table schema.tbl_name alter column column_name type varchar(5) using column_name::varchar(5);
Is there any way (function) that I could list all the views related to the table?
Use this query:
select
u.view_schema schema_name,
u.view_name,
u.table_schema referenced_table_schema,
u.table_name referenced_table_name,
v.view_definition
from information_schema.view_table_usage u
join information_schema.views v on u.view_schema = v.table_schema
and u.view_name = v.table_name
where u.table_schema not in ('information_schema', 'pg_catalog')
order by u.view_schema, u.view_name
Credit: Dataedo.com's article List tables used by a view in PostgreSQL database

Delete Duplicate rows in several Postgresql tables

I have a postgres database with several tables like table1, table2, table3. More than 1000 tables.
I imported all of these tables from a script. And apparently the script had issues to import.
Many tables have duplicate rows (all values exactly same).
I am able to go in each table and then delete duplicate row using Dbeaver, but because there are over 1000 tables, it is very time consuming.
Example of tables:
table1
name gender age
a m 20
a m 20
b f 21
b f 21
table2
fruit hobby
x running
x running
y stamp
y stamp
How can I do the following:
Identify tables in postgres with duplicate rows.
Delete all duplicate rows, leaving 1 record.
I need to do this on all 1000+ tables at once.
As you want to automate your deduplication of all table, you need to use plpgsql function where you can write dynamic queries to achieve it.
Try This function:
create or replace function func_dedup(_schemaname varchar) returns void as
$$
declare
_rec record;
begin
for _rec in select table_name from information_schema. tables where table_schema=_schemaname
loop
execute format('CREATE TEMP TABLE tab_temp as select DISTINCT * from '||_rec.table_name);
execute format('truncate '||_rec.table_name);
execute format('insert into '||_rec.table_name||' select * from tab_temp');
execute format('drop table tab_temp');
end loop;
end;
$$
language plpgsql
Now call your function like below:
select * from func_dedup('your_schema'); --
demo
Steps:
Get the list of all tables in your schema by using below query and loop it for each table.
select table_name from information_schema. tables where table_schema=_schemaname
Insert all distinct records in a TEMP TABLE.
Truncate your main table.
Insert all your data from TEMP TABLE to main table.
Drop the TEMP TABLE. (here dropping temp table is important we have to reuse it for next loop cycle.)
Note - if your tables are very large in size the consider using Regular Table instead of TEMP TABLE.

IF... ELSE... two mutually exclusive inserts INTO #temptable

I need to insert either set A or set B of records into a #temptable, depending on certain condition
My pseudo-code:
IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1;
IF {some-condition}
SELECT {columns}
INTO #t1
FROM {some-big-table}
WHERE {some-filter}
ELSE
SELECT {columns}
INTO #t1
FROM {some-other-big-table}
WHERE {some-other-filter}
The two SELECTs above are exclusive (guaranteed by the ELSE operator). However, SQL compiler tries to outsmart me and throws the following message:
There is already an object named '#t1' in the database.
My idea of "fixing" this is to create #t1 upfront and then executing a simple INSERT INTO (instead of SELECT... INTO). But I like minimalism and am wondering whether this can be achieved in an easier way i.e. without explicit CREATE TABLE #t1 upfront.
Btw why is it NOT giving me an error on a conditional DROP TABLE in the first line? Just wondering.
You can't have 2 temp tables with the same name in a single SQL batch. One of the MSDN article says "If more than one temporary table is created inside a single stored procedure or batch, they must have different names". You can have this logic with 2 different temp tables or table variable/temp table declared outside the IF-Else block.
Using a Dyamic sql we can handle this situation. As a developoer its not a good practice. Best to use table variable or temp table.
IF 1=2
BEGIN
EXEC ('SELECT 1 ID INTO #TEMP1
SELECT * FROM #TEMP1
')
END
ELSE
EXEC ('SELECT 2 ID INTO #TEMP1
SELECT * FROM #TEMP1
')

Postgres run statement against multiple schemas

I have a mult-tenant application where tenants are set up on different schemas within the same database. The reason being that they have some shared data they use on one of the schemas.
Up until now I've been using a bash script with a list of the schemas in it that needs to be updated whenever a new schema is added and I need to do things like table schema changes across the accounts. For instance adding a new column to a table.
Is there a way in Postgres, psql, etc... to run for instance
ALTER TABLE some_table ADD COLUMN some_column TEXT NOT NULL DEFAULT '';
without having to do string replacement in another script like bash for instance.
So in other words is there an easy enough way to get the schemas, and write in psql a for loop that will iterate through the schemas and run the statement each by setting search_path for instance.
The reason being that the number of tenants is growing, and new tenants can be added by admin users that aren't devs, so I'm constantly updating my shell scripts. This will only grow exponentially. Is there a standard way of handling this kind of problem?
You can do that with a little PL/pgSQL block:
do
$$
declare
s_rec record;
begin
for s_rec in select schema_name
from information_schema.schemata
where schema_name not in ('pg_catalog', 'information_schema')
loop
execute format ('ALTER TABLE if exists %I.some_table ADD COLUMN some_column TEXT NOT NULL DEFAULT ''''), s_rec.schema_name);
end loop;
end;
$$
The if exists will make sure the statement doesn't fail if that table doesn't exist in the schema.
If you over-simplified your question and want in fact run complete scripts once for each schema, generating a script for each schema that includes the actual script is probably easier:
select concat(format('set search_path = %I;', schema_name),
chr(10),
'\i complete_migration_script.sql')
from information_schema.schemata
where schema_name not in ('pg_catalog', 'information_schema')
You can spool the output of that statement into a file and then run that file using psql (of course you need to replace complete_migration_script.sql with the actual name of your script)

Create a temporary table from a selection or insert if table already exist

How to create a temporary table, if it does not already exist, and add the selected rows to it?
CREATE TABLE AS
is the simplest and fastest way:
CREATE TEMP TABLE tbl AS
SELECT * FROM tbl WHERE ... ;
Do not use SELECT INTO. See:
Combine two tables into a new one so that select rows from the other one are ignored
Not sure whether table already exists
CREATE TABLE IF NOT EXISTS ... was introduced in version Postgres 9.1.
For older versions, use the function provided in this related answer:
PostgreSQL create table if not exists
Then:
INSERT INTO tbl (col1, col2, ...)
SELECT col1, col2, ...
Chances are, something is going wrong in your code if the temp table already exists. Make sure you don't duplicate data in the table or something. Or consider the following paragraph ...
Unique names
Temporary tables are only visible within your current session (not to be confused with transaction!). So the table name cannot conflict with other sessions. If you need unique names within your session, you could use dynamic SQL and utilize a SEQUENCE:
Create once:
CREATE SEQUENCE tablename_helper_seq;
You could use a DO statement (or a plpgsql function):
DO
$do$
BEGIN
EXECUTE
'CREATE TEMP TABLE tbl' || nextval('tablename_helper_seq'::regclass) || ' AS
SELECT * FROM tbl WHERE ... ';
RAISE NOTICE 'Temporary table created: "tbl%"' || ', lastval();
END
$do$;
lastval() and currval(regclass) are instrumental to return the dynamically created table name.