Postgres - How to drop all tables in a database except for 3 - postgresql

I know that to drop a table in a database is as follows, but if I have a database that has over a dozen tables and I only need to keep 3 of them, am I able to delete all but the 3 with only one command?
DROP TABLE IF EXISTS c_note RESTRICT;

Yes, but you need to enumerate over all the tables you want to drop. There's no command to drop all but 3. So, if you had the following tables:
foo
bar
baz
narf
poit
troz
And you wanted to drop the first three and keep the last three, you would use the command:
DROP TABLE foo, bar, baz;
If you know the tables all exist, there's no need for IF EXISTS, although it won't hurt. RESTRICT is also not needed -- that's the default (the opposite is CASCADE, where you also drop dependant objects).
SQL Doc

The following query will simmply delete all the tables but keep your schema
select 'drop table if exists ' || tablename || ' cascade;'
from pg_tables
where schemaname = 'public'
Write down a query where you can skip three tables by name
select 'drop table if exists ' || tablename || ' cascade;'
from pg_tables
where schemaname = 'public'
and tablename not in (:tbaleNamesToKeep);

I had 192 tables, so manually writing all tables out was infeasible. My strategy was to select all table names, remove the tables I wanted to keep and then run a DROP on the rest.
1. Select all tables
SELECT tablename FROM pg_tables
When you select, copy and paste the results, the text should look something like this:
"table1"
"table2"
"table3"
...
2. Remove the tables you want to keep
So let's say you want to keep table2, you just remove the line.
"table1"
"table3"
...
3. Add commas with text replacement
Replace "\n with ",\n.
To do this, I use regexr.com, but any text editor will do.
"table1",
"table3",
...
4. Create and run the final PSQL statement
DROP TABLE
"table1",
"table3",
...

Related

Find a table in a schema without knowing in advance

Is it possible to easily see what tables exist in what schemas, at a glance?
So far I have had to connect to a database, view the schemas, then change the search path to one of the schemas and then list the tables. I had to do this for multiple schemas until I found the table I was looking for.
What if there is a scenario where you inherit a poorly documented database and you want to find a specific table in hundreds of schemas?
Ideally I imagine some output like so;
SCHEMA TABLE
--------------------
schema1 table1
schema2 table2
schema2 table1
--------------------
Or even the more standard <SCHEMA_NAME>.<TABLE_NAME>;
schema1.table1
schema2.table2
schema2.table1
The latter output would be even better since you could simply check the table using copy-paste;
my-database=# \d schema2.table1
Ideally I'm hoping I missed a built-in command to find this. I don't really want to create and memorize a lengthy SQL command to get this (somewhat basic) information.
You can make use of pg_tables
SELECT schemaname, tablename,
quote_ident(schemaname) || '.' || quote_ident(tablename)
FROM pg_tables
WHERE tablename = 'test';

How to add ONE column to ALL tables in postgresql schema

question is pretty simple, but can't seem to find a concrete answer anywhere.
I need to update all tables inside my postgresql schema to include a timestamp column with default NOW(). I'm wondering how I can do this via a query instead of having to go to each individual table. There are several hundred tables in the schema and they all just need to have the one column added with the default value.
Any help would be greatly appreciated!
The easy way with psql, run a query to generate the commands, save and run the results
-- Turn off headers:
\t
-- Use SQL to build SQL:
SELECT 'ALTER TABLE public.' || table_name || ' add fecha timestamp not null default now();'
FROM information_schema.tables
WHERE table_type = 'BASE TABLE' AND table_schema='public';
-- If the output looks good, write it to a file and run it:
\g out.tmp
\i out.tmp
-- or if you don't want the temporal file, use gexec to run it:
\gexec

postgresql - how to use a cursor or select statement to generate mulitple DML statements

New to postgres and I'm using Postgresql 9.3. Is there a way with postgresql to generate a file with multiple DML statements?
For example, I want to select table name where tablename like '_foo%' and then rename all those tables to '_bar%'. Do I need to do this in a cursor or can I do this within a select statement? (like in Oracle)
ALTER TABLE RENAME tst1_foo TO tst1_bar;
ALTER TABLE RENAME tst2_foo TO tst2_bar;
ALTER TABLE RENAME tst3_foo TO tst3_bar;
I'd like to print those out to a .sql file.
Please provide a basic example if possible. Thanks.
You can use psql and the pg_tables system view. Set the output to unaligned mode:
\a
Set the output to show only rows:
\t on
Send output to your file:
\o yourfile.sql
Run the query:
SELECT 'ALTER TABLE RENAME ' || tablename || ' TO ' ||
REGEXP_REPLACE ( tablename, '_foo$', '_bar' ) || ';'
FROM pg_tables
WHERE tablename LIKE '%_foo';
Close the file:
\o
and/or close psql:
\q

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.

How do I drop all tables in psql (PostgreSQL interactive terminal) that starts with a common word?

How do I drop all tables whose name start with, say, doors_? Can I do some sort of regex using the drop table command?
I prefer not writing a custom script but all solutions are welcomed. Thanks!
This script will generate the DDL commands to drop them all:
SELECT 'DROP TABLE ' || t.oid::regclass || ';'
FROM pg_class t
-- JOIN pg_namespace n ON n.oid = t.relnamespace -- to select by schema
WHERE t.relkind = 'r'
AND t.relname ~~ E'doors\_%' -- enter search term for table here
-- AND n.nspname ~~ '%myschema%' -- optionally select by schema(s), too
ORDER BY 1;
The cast t.oid::regclass makes the syntax work for mixed case identifiers, reserved words or special characters in table names, too. It also prevents SQL injection and prepends the schema name where necessary. More about object identifier types in the manual.
About the schema search path.
You could automate the dropping, too, but it's unwise not to check what you actually delete before you do.
You could append CASCADE to every statement to DROP depending objects (views and referencing foreign keys). But, again, that's unwise unless you know very well what you are doing. Foreign key constraints are no big loss, but this will also drop all dependent views entirely. Without CASCADE you get error messages informing you which objects prevent you from dropping the table. And you can then deal with it.
I normally use one query to generate the DDL commands for me based on some of the metadata tables and then run those commands manually. For example:
SELECT 'DROP TABLE ' || tablename || ';' FROM pg_tables
WHERE tablename LIKE 'prefix%' AND schemaname = 'public';
This will return a bunch of DROP TABLE xxx; queries, which I simply copy&paste to the console. While you could add some code to execute them automatically, I prefer to run them on my own.