why can I not parse variable parsed from outside? - postgresql

I am trying to make a drop database script, which I would have to trigger using psql.
psql ... -f reset-database.sql -v dbname=$database
The problem is that I am not able to access the variable :dbname in my script.
DO
$$
BEGIN
IF EXISTS (SELECT EXISTS( SELECT datname FROM pg_catalog.pg_database WHERE datname = :dbname)) THEN
UPDATE pg_database SET datallowconn = 'false' WHERE datname = :dbname;
SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = :dbname;
DROP DATABASE IF EXISTS :dbname;
END IF;
END
$$
This is executed as is, and :dbname is not replaced with the database name parsed in as as variable? Why? And how do I parse it?

The variable substitution will not work in a DO statement, because the statement body is a (dollar quoted) string literal. Otherwise, it should work fine, but you have to use single quotes in your metadata query. Besides, you cannot run DROP DATABASE inside a DO statement, since you cannot run it inside a transaction.
Also, don't update catalog tables.
You can use psql's \if for conditional processing:
SELECT EXISTS (
SELECT 1 FROM pg_catalog.pg_database
WHERE datname = :'dbname'
) AS have_db \gset
\if :have_db
ALTER DATABASE :dbname ALLOW_CONNECTIONS FALSE;
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = :'dbname';
DROP DATABASE :dbname;
\endif
From PostgreSQL v13 on, this is much simpler:
DROP DATABASE IF EXISTS :dbname WITH (FORCE);

Related

How to create a function in PostgreSQL like SQL Server BACKUP DATABASE TO DISK

I'm trying without success to create a function in Postgres that save a table or database taking one or two parameters. In this case I was trying to create it with only one parameter(name of the table or database) and backup this table/db
--SELECT backup_table(sports)
CREATE FUNCTION backup_table(TEXT) RETURNS BOOLEAN AS
$$
DECLARE
table_x ALIAS FOR $1;
BEGIN
COPY table_x FROM 'C:/path/backup_db' WITH (FORMAT CSV);
RAISE NOTICE 'Saved correctly the table %',$1;
RETURN BOOLEAN;
END;
$$ LANGUAGE plpgsql;
I've always receive the error when I try to execute the function SELECT backup_table(sports):
"The column sports doesnt exists."
SQL state: 42703
Character: 21
The idea is to create the function like the equivalent of SQL Server BACKUP DATABASE TO DISK, or equivalent to pg_dump command
pg_dump -U -W -F t sports > C:/path/backup_db;
I know about SQL but now I'm just stuck with this error.

Equivalent of PRAGMA table_info(table) for Postgres SQL?

I am working with a script made for SQLite but I need to adapt it to a PostgreSQL database and this line is always returning an error:
PRAGMA table_info(table)
How can I get an equivalent result on postgres >
Found it !
SELECT *
FROM information_schema.columns
WHERE table_name = 'table_name'

PostgreSQL: Assign generated password in CREATE ROLE

I'm trying to setup a DB initialization script. I need to avoid manual configuration steps AND hardcoded passwords in the source code. I have a function which generates random passwords (adapted from https://www.postgresql.org/message-id/46685BBD.3070809#hagander.net).
The function works (e.g. select generate_random_password()), but I cannot get the "CREATE ROLE" command to accept anything except raw strings.
Does anyone know how I can set the password with the return value of a function that's already been declared? Do I need to mess around with EVALUATE (like a shell-script using eval)?
This:
CREATE ROLE my_user WITH LOGIN CREATEDB PASSWORD generate_random_password();
Yields: SQL Error [42601]: ERROR: syntax error at or near "generate_random_password"
This:
DO $$
DECLARE
passwd varchar := generate_random_password();
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'my_user') THEN
CREATE ROLE my_user WITH LOGIN CREATEDB PASSWORD passwd;
END IF;
END
$$;
Yields: SQL Error [42601]: ERROR: syntax error at or near "passwd" Position: 208
You will need dynamic SQL:
DO $$
DECLARE
passwd varchar := generate_random_password();
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'my_user') THEN
EXECUTE FORMAT(
'CREATE ROLE my_user WITH LOGIN CREATEDB PASSWORD %L', passwd
);
END IF;
END
$$;

Using pg_dump with no owner information still outputting role information

I dumped a database using pg_dump -O -x expecting all ownership and role information to be ignored, however, it is still including specific mentions to manager roles in the original database which are failing to be imported because they don't exist in the new database which I'm importing into. See the snippet of the dump.sql file:
--
-- Name: reassign_owned(); Type: FUNCTION; Schema: public; Owner: -
--
CREATE FUNCTION reassign_owned() RETURNS event_trigger
LANGUAGE plpgsql
AS $$
begin
-- do not execute if member of rds_superuser
IF EXISTS (select 1 from pg_catalog.pg_roles where rolname = 'rds_superuser')
AND pg_has_role(current_user, 'rds_superuser', 'member') THEN
RETURN;
END IF;
-- do not execute if not member of manager role
IF NOT pg_has_role(current_user, 'rdsbroker_xxxxx_manager', 'member') THEN
RETURN;
END IF;
-- do not execute if superuser
IF EXISTS (SELECT 1 FROM pg_user WHERE usename = current_user and usesuper = true) THEN
RETURN;
END IF;
EXECUTE 'reassign owned by "' || current_user || '" to "rdsbroker_xxxxx_manager"';
end
$$;
-O means that pg_dump itself does not emit ownership information. It doesn't cause it to edit the source code of any functions it might dump, in an attempt to prevent those functions from doing what they were written to do.
I've done a quick search in pg_dump and pg_restore source code and I see no usage of REASSIGN OWNED statement.

How can I drop all the tables in a PostgreSQL database?

How can I drop all tables in PostgreSQL, working from the command line?
I don't want to drop the database itself, just all tables and all the data in them.
If all of your tables are in a single schema, this approach could work (below code assumes that the name of your schema is public)
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
If you are using PostgreSQL 9.3 or later, you may also need to restore the default grants.
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
You can write a query to generate a SQL script like this:
select 'drop table "' || tablename || '" cascade;' from pg_tables;
Or:
select 'drop table if exists "' || tablename || '" cascade;' from pg_tables;
In case some tables are automatically dropped due to cascade option in a previous sentence.
Additionally, as stated in the comments, you might want to filter the tables you want to drop by schema name:
select 'drop table if exists "' || tablename || '" cascade;'
from pg_tables
where schemaname = 'public'; -- or any other schema
And then run it.
Glorious COPY+PASTE will also work.
The most accepted answer as of this writing (January 2014) is:
drop schema public cascade;
create schema public;
This does work, however, if your intention is to restore the public schema to its original state this does not fully accomplish the task. Under pgAdmin III for PostgreSQL 9.3.1, if you click on the "public" schema created this way and look in the "SQL pane" you will see the following:
-- Schema: public
-- DROP SCHEMA public;
CREATE SCHEMA public
AUTHORIZATION postgres;
However, by contrast a brand new database will have the following:
-- Schema: public
-- DROP SCHEMA public;
CREATE SCHEMA public
AUTHORIZATION postgres;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public
IS 'standard public schema';
For me using a python web framework which creates database tables (web2py), using the former caused problems:
<class 'psycopg2.ProgrammingError'> no schema has been selected to create in
So to my mind the fully correct answer is:
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public IS 'standard public schema';
Also note to issue these commands in pgAdmin III, I used the Query tool ( magnifying glass icon "Execute abritrary SQL queries") or you could use Plugins-> PSQL Console
Note
If you have any extensions installed they will be dropped when you drop the schema, so you should make note of what you need installed and then execute statements as necessary. E.g.
CREATE EXTENSION postgis;
You can drop all tables with
DO $$ DECLARE
r RECORD;
BEGIN
-- if the schema you operate on is not "current", you will want to
-- replace current_schema() in query with 'schematodeletetablesfrom'
-- *and* update the generate 'DROP...' accordingly.
FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
END LOOP;
END $$;
IMO this is better than drop schema public, because you don't need to recreate the schema and restore all the grants.
Additional bonus that this doesn't require external scripting language, nor copy-pasting of generated SQL back to the interpreter.
If everything you want to drop is owned by the same user, then you can use:
drop owned by the_user;
This will drop everything that the user owns.
That includes materialized views, views, sequences, triggers, schemas, functions, types, aggregates, operators, domains and so on (so, really: everything) that the_user owns (=created).
You have to replace the_user with the actual username, currently there is no option to drop everything for "the current user". The upcoming 9.5 version will have the option drop owned by current_user.
More details in the manual: http://www.postgresql.org/docs/current/static/sql-drop-owned.html
This is a really interesting question, and you'll get it done in Multiple ways::
1. By dropping and recreating the current schema
Here, In general, we have a public schema by default. So, I'm using it as an instance.
-- Recreate the schema
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
-- Restore default permissions
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
If you are using PostgreSQL 9.3 or greater, you may also need to restore the default grants.
Pros:
This will clean an entire Schema and re-create it as a new one.
Cons:
You'll lose other entities too like Functions, Views, Materialized views, etc.
2. By using fetching all table names from pg_tables table.
PostgreSQL stores all the tables on its record table named pg_table.
SELECT
'DROP TABLE IF EXISTS "' || tablename || '" CASCADE;'
from
pg_tables WHERE schemaname = 'public';
As you can see, By the use of subquery, We can remove the entire tables from the schema.
Pros:
When the other data entities are Important and you want to delete only tables from the schema, this approach will really helpful to you.
3. Terminal
Login using postgres user on your shell
$ sudo -u postgres psql
Connect your database
$ \c mydatabase
Paste these commands:
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
Note: This bunch of commands is similar to the first point, so the Pros and cons will remain the same..
As per Pablo above, to just drop from a specific schema, with respect to case:
select 'drop table "' || tablename || '" cascade;'
from pg_tables where schemaname = 'public';
drop schema public cascade;
should do the trick.
Following steps might be helpful (For linux users):
At first enter the postgres command prompt by following command:
sudo -u postgres psql
Enter the database by this command (my database name is: maoss):
\c maoss
Now enter the command for droping all tables:
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
Now exit from psql by following command:
\q
Following Pablo and LenW, here's a one-liner that does it all both preparing and then executing:
psql -U $PGUSER $PGDB -t -c "select 'drop table \"' || tablename || '\" cascade;' from pg_tables where schemaname = 'public'" | psql -U $PGUSER $PGDB
NB: either set or replace $PGUSER and $PGDB with the values you want
If you have the PL/PGSQL procedural language installed you can use the following to remove everything without a shell/Perl external script.
DROP FUNCTION IF EXISTS remove_all();
CREATE FUNCTION remove_all() RETURNS void AS $$
DECLARE
rec RECORD;
cmd text;
BEGIN
cmd := '';
FOR rec IN SELECT
'DROP SEQUENCE ' || quote_ident(n.nspname) || '.'
|| quote_ident(c.relname) || ' CASCADE;' AS name
FROM
pg_catalog.pg_class AS c
LEFT JOIN
pg_catalog.pg_namespace AS n
ON
n.oid = c.relnamespace
WHERE
relkind = 'S' AND
n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
pg_catalog.pg_table_is_visible(c.oid)
LOOP
cmd := cmd || rec.name;
END LOOP;
FOR rec IN SELECT
'DROP TABLE ' || quote_ident(n.nspname) || '.'
|| quote_ident(c.relname) || ' CASCADE;' AS name
FROM
pg_catalog.pg_class AS c
LEFT JOIN
pg_catalog.pg_namespace AS n
ON
n.oid = c.relnamespace WHERE relkind = 'r' AND
n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
pg_catalog.pg_table_is_visible(c.oid)
LOOP
cmd := cmd || rec.name;
END LOOP;
FOR rec IN SELECT
'DROP FUNCTION ' || quote_ident(ns.nspname) || '.'
|| quote_ident(proname) || '(' || oidvectortypes(proargtypes)
|| ');' AS name
FROM
pg_proc
INNER JOIN
pg_namespace ns
ON
(pg_proc.pronamespace = ns.oid)
WHERE
ns.nspname =
'public'
ORDER BY
proname
LOOP
cmd := cmd || rec.name;
END LOOP;
EXECUTE cmd;
RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT remove_all();
Rather than type this in at the "psql" prompt I would suggest you copy it to a file and then pass the file as input to psql using the "--file" or "-f" options:
psql -f clean_all_pg.sql
Credit where credit is due: I wrote the function, but think the queries (or the first one at least) came from someone on one of the pgsql mailing lists years ago. Don't remember exactly when or which one.
If you want to nuke all tables anyway, you can dispense with niceties such as CASCADE by putting all tables into a single statement. This also makes execution quicker.
SELECT 'TRUNCATE TABLE ' || string_agg('"' || tablename || '"', ', ') || ';'
FROM pg_tables WHERE schemaname = 'public';
Executing it directly:
DO $$
DECLARE tablenames text;
BEGIN
tablenames := string_agg('"' || tablename || '"', ', ')
FROM pg_tables WHERE schemaname = 'public';
EXECUTE 'TRUNCATE TABLE ' || tablenames;
END; $$
Replace TRUNCATE with DROP as applicable.
I modified Pablo's answer slightly for the convenience of having the generated SQL commands returned as one single string:
select string_agg('drop table "' || tablename || '" cascade', '; ')
from pg_tables where schemaname = 'public'
Just in case... Simple Python script that clean Postgresql database
import psycopg2
import sys
# Drop all tables from a given database
try:
conn = psycopg2.connect("dbname='akcja_miasto' user='postgres' password='postgres'")
conn.set_isolation_level(0)
except:
print "Unable to connect to the database."
cur = conn.cursor()
try:
cur.execute("SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name")
rows = cur.fetchall()
for row in rows:
print "dropping table: ", row[1]
cur.execute("drop table " + row[1] + " cascade")
cur.close()
conn.close()
except:
print "Error: ", sys.exc_info()[1]
Make sure that after copying it the indentation is right since Python relies on it.
Use this script in pgAdmin:
DO $$
DECLARE
brow record;
BEGIN
FOR brow IN (select 'drop table "' || tablename || '" cascade;' as table_name from pg_tables where schemaname = 'public') LOOP
EXECUTE brow.table_name;
END LOOP;
END; $$
If you want delete data (not delete table):
-- Truncate tables and restart sequnces
SELECT 'TRUNCATE TABLE "' || table_schema || '"."' || table_name || '" RESTART IDENTITY CASCADE;'
FROM information_schema.tables
WHERE table_catalog = '<database>' AND table_schema = '<schema>';
Or if you want drop table your can use this sql:
-- For tables
SELECT 'DROP TABLE "' || table_schema || '"."' || table_name || '" CASCADE;'
FROM information_schema.tables
WHERE table_catalog = '<database>' AND table_schema = '<schema>';
-- For sequences
SELECT 'DROP SEQUENCE d_a_seq "' || sequence_schema || '"."' || sequence_name || '";'
FROM information_schema.sequences
WHERE sequence_catalog = '<database>' AND sequence_schema = '<schema>';
Just execute the query bellow:
DO $$ DECLARE
r RECORD;
BEGIN
FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
END LOOP;
END $$;
You can use the string_agg function to make a comma-separated list, perfect for DROP TABLE.
From a bash script:
#!/bin/bash
TABLES=`psql $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public'"`
echo Dropping tables:${TABLES}
psql $PGDB --command "DROP TABLE IF EXISTS ${TABLES} CASCADE"
Note: my answer is about really deleting the tables and other database objects; for deleting all data in the tables, i.e. truncating all tables, Endre Both has provided a similarily well-executed (direct execution) statement a month later.
For the cases where you can’t just DROP SCHEMA public CASCADE;, DROP OWNED BY current_user; or something, here’s a stand-alone SQL script I wrote, which is transaction-safe (i.e. you can put it between BEGIN; and either ROLLBACK; to just test it out or COMMIT; to actually do the deed) and cleans up “all” database objects… well, all those used in the database our application uses or I could sensibly add, which is:
triggers on tables
constraints on tables (FK, PK, CHECK, UNIQUE)
indicēs
VIEWs (normal or materialised)
tables
sequences
routines (aggregate functions, functions, procedures)
all nōn-default (i.e. not public or DB-internal) schemata “we” own: the script is useful when run as “not a database superuser”; a superuser can drop all schemata (the really important ones are still explicitly excluded, though)
extensions (user-contributed but I normally deliberately leave them in)
Not dropped are (some deliberate; some only because I had no example in our DB):
the public schema (e.g. for extension-provided stuff in them)
collations and other locale stuff
event triggers
text search stuff, … (see here for other stuff I might have missed)
roles or other security settings
composite types
toast tables
FDW and foreign tables
This is really useful for the cases when the dump you want to restore is of a different database schema version (e.g. with Debian dbconfig-common, Flyway or Liquibase/DB-Manul) than the database you want to restore it into.
I’ve also got a version which deletes “everything except two tables and what belongs to them” (a sequence, tested manually, sorry, I know, boring) in case someone is interested; the diff is small. Contact me or check this repo if interested.
SQL
-- Copyright © 2019, 2020
-- mirabilos <t.glaser#tarent.de>
--
-- Provided that these terms and disclaimer and all copyright notices
-- are retained or reproduced in an accompanying document, permission
-- is granted to deal in this work without restriction, including un‐
-- limited rights to use, publicly perform, distribute, sell, modify,
-- merge, give away, or sublicence.
--
-- This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
-- the utmost extent permitted by applicable law, neither express nor
-- implied; without malicious intent or gross negligence. In no event
-- may a licensor, author or contributor be held liable for indirect,
-- direct, other damage, loss, or other issues arising in any way out
-- of dealing in the work, even if advised of the possibility of such
-- damage or existence of a defect, except proven that it results out
-- of said person’s immediate fault when using the work as intended.
-- -
-- Drop everything from the PostgreSQL database.
DO $$
DECLARE
q TEXT;
r RECORD;
BEGIN
-- triggers
FOR r IN (SELECT pns.nspname, pc.relname, pt.tgname
FROM pg_catalog.pg_trigger pt, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
WHERE pns.oid=pc.relnamespace AND pc.oid=pt.tgrelid
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pt.tgisinternal=false
) LOOP
EXECUTE format('DROP TRIGGER %I ON %I.%I;',
r.tgname, r.nspname, r.relname);
END LOOP;
-- constraints #1: foreign key
FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
FROM pg_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pcon.contype='f'
) LOOP
EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
r.nspname, r.relname, r.conname);
END LOOP;
-- constraints #2: the rest
FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
FROM pg_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pcon.contype<>'f'
) LOOP
EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
r.nspname, r.relname, r.conname);
END LOOP;
-- indicēs
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind='i'
) LOOP
EXECUTE format('DROP INDEX %I.%I;',
r.nspname, r.relname);
END LOOP;
-- normal and materialised views
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind IN ('v', 'm')
) LOOP
EXECUTE format('DROP VIEW %I.%I;',
r.nspname, r.relname);
END LOOP;
-- tables
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind='r'
) LOOP
EXECUTE format('DROP TABLE %I.%I;',
r.nspname, r.relname);
END LOOP;
-- sequences
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind='S'
) LOOP
EXECUTE format('DROP SEQUENCE %I.%I;',
r.nspname, r.relname);
END LOOP;
-- extensions (only if necessary; keep them normally)
FOR r IN (SELECT pns.nspname, pe.extname
FROM pg_catalog.pg_extension pe, pg_catalog.pg_namespace pns
WHERE pns.oid=pe.extnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
) LOOP
EXECUTE format('DROP EXTENSION %I;', r.extname);
END LOOP;
-- aggregate functions first (because they depend on other functions)
FOR r IN (SELECT pns.nspname, pp.proname, pp.oid
FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns, pg_catalog.pg_aggregate pagg
WHERE pns.oid=pp.pronamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pagg.aggfnoid=pp.oid
) LOOP
EXECUTE format('DROP AGGREGATE %I.%I(%s);',
r.nspname, r.proname,
pg_get_function_identity_arguments(r.oid));
END LOOP;
-- routines (functions, aggregate functions, procedures, window functions)
IF EXISTS (SELECT * FROM pg_catalog.pg_attribute
WHERE attrelid='pg_catalog.pg_proc'::regclass
AND attname='prokind' -- PostgreSQL 11+
) THEN
q := 'CASE pp.prokind
WHEN ''p'' THEN ''PROCEDURE''
WHEN ''a'' THEN ''AGGREGATE''
ELSE ''FUNCTION''
END';
ELSIF EXISTS (SELECT * FROM pg_catalog.pg_attribute
WHERE attrelid='pg_catalog.pg_proc'::regclass
AND attname='proisagg' -- PostgreSQL ≤10
) THEN
q := 'CASE pp.proisagg
WHEN true THEN ''AGGREGATE''
ELSE ''FUNCTION''
END';
ELSE
q := '''FUNCTION''';
END IF;
FOR r IN EXECUTE 'SELECT pns.nspname, pp.proname, pp.oid, ' || q || ' AS pt
FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns
WHERE pns.oid=pp.pronamespace
AND pns.nspname NOT IN (''information_schema'', ''pg_catalog'', ''pg_toast'')
' LOOP
EXECUTE format('DROP %s %I.%I(%s);', r.pt,
r.nspname, r.proname,
pg_get_function_identity_arguments(r.oid));
END LOOP;
-- nōn-default schemata we own; assume to be run by a not-superuser
FOR r IN (SELECT pns.nspname
FROM pg_catalog.pg_namespace pns, pg_catalog.pg_roles pr
WHERE pr.oid=pns.nspowner
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast', 'public')
AND pr.rolname=current_user
) LOOP
EXECUTE format('DROP SCHEMA %I;', r.nspname);
END LOOP;
-- voilà
RAISE NOTICE 'Database cleared!';
END; $$;
Tested, except later additions (extensions contributed by Clément Prévost), on PostgreSQL 9.6 (jessie-backports). Aggregate removal tested on 9.6 and 12.2, procedure removal tested on 12.2 as well. Bugfixes and further improvements welcome!
You need to drop tables and sequences, here is what worked for me
psql -qAtX -c "select 'DROP TABLE IF EXISTS ' || quote_ident(table_schema) || '.' || quote_ident(table_name) || ' CASCADE;' FROM information_schema.tables where table_type = 'BASE TABLE' and not table_schema ~ '^(information_schema|pg_.*)$'" | psql -qAtX
psql -qAtX -c "select 'DROP SEQUENCE IF EXISTS ' || quote_ident(relname) || ' CASCADE;' from pg_statio_user_sequences;" | psql -qAtX
before you run the command you might need to sudo/su to the postgres user or (export connection details PGHOST, PGPORT, PGUSER and PGPASSWORD) and then export PGDATABASE=yourdatabase
Rake task for Rails for destroy all tables in current database
namespace :db do
# rake db:drop_all_tables
task drop_all_tables: :environment do
query = <<-QUERY
SELECT
table_name
FROM
information_schema.tables
WHERE
table_type = 'BASE TABLE'
AND
table_schema NOT IN ('pg_catalog', 'information_schema');
QUERY
connection = ActiveRecord::Base.connection
results = connection.execute query
tables = results.map do |line|
table_name = line['table_name']
end.join ", "
connection.execute "DROP TABLE IF EXISTS #{ tables } CASCADE;"
end
end
I enhanced the bash method from jamie by taking care of views because his only respects the table type "base table" which is the default.
following bash code deletes the views first and then all the rest
#!/usr/bin/env bash
PGDB="yourDB"
# By exporting user & pass your dont need to interactively type them on execution
export PGUSER="PGusername"
export PGPASSWORD="PGpassword"
VIEWS=`psql -d $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public' AND table_type='VIEW'"`
BASETBLS=`psql -d $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE'"`
echo Dropping views:${VIEWS}
psql $PGDB --command "DROP VIEW IF EXISTS ${VIEWS} CASCADE"
echo Dropping tables:${BASETBLS}
psql $PGDB --command "DROP TABLE IF EXISTS ${BASETBLS} CASCADE"
in a Windows batch file:
#echo off
FOR /f "tokens=2 delims=|" %%G IN ('psql --host localhost --username postgres --command="\dt" YOUR_TABLE_NAME') DO (
psql --host localhost --username postgres --command="DROP table if exists %%G cascade" sfkb
echo table %%G dropped
)
Using PSQL with \gexec
This is a far more comprehensive query then the ones thus far, as it will work with special table names.
SELECT FORMAT('DROP TABLE %I.%I.%I CASCADE;', table_catalog, table_schema, table_name)
FROM information_schema.tables
WHERE table_type = 'BASE TABLE'
AND table_schema <> 'information_schema'
AND table_schema NOT LIKE 'pg_%';
You can preview the commands to be run, and you can execute the output of this query by typing \gexec after you run it in psql.
NOTE: The use of CASCADE will drop all things (like VIEWs) that depend on the table
The easiest way is to drop the public schema as others have suggested in previous answers. However, this is NOT a good way. You never know what has been done to the public schema that has since been forgotten and was not documented. You also don't know if this will work the same into the future. In V9, it would have been fine, but in V10 all your users would loose access to the schema, and must be granted access again otherwise your application will break. I haven't checked V11, but the point is that you never know what will break as you move from machine to machine, site to site or version to version. It also cannot be done if you are a user that has access to the database, but not to the schema.
If you need to do this programmatically then other answers above cover this, but one thing the answers above don't consider is to get Postgres to do the work for you. If you use pg_dump with the -c option as below:
sudo su postgres -c "pg_dump -U postgres WhateverDB -c -f "/home/Anyone/DBBackupWhateverDB-ServerUnscheduled.sql""
That will create a DB restore script with sql statements that will delete all the tables.
If the only purpose in asking the question was to delete the tables prior to restore, then your restore will do the work for you.
However, if you need it for something else, you can simply copy the drop statements from the sql script.
well, since I like working from the command line...
psql -U <user> -d <mydb> -c '\dt' | cut -d ' ' -f 4 | sed -e "s/^/drop table if exists /" | sed -e "s/$/;/"
-c '\dt' will invoke the list tables command.
List of relations
Schema | Name | Type | Owner
--------+-------------------+-------+----------
public | _d_psidxddlparm | table | djuser
public | _d_psindexdefn | table | djuser
cut -d ' ' -f 4 now, pipe its output to grab the 4th field (when using space as separator), which is the table.
sed is then used to prefix a drop table and suffix the ; command separator.
| egrep '_d_' - Pipe it into grep some more and you can be more selective about which tables you drop.
drop table if exists _d_psidxddlparm;
drop table if exists _d_psindexdefn;
Note: as written, this will generate bogus rows for the \dt commands output of column headers and total rows at the end. I avoid that by grepping, but you could use head and tail.
A terminal based approach using psql worked best for me. I even created a bash function because it is convenient for development:
psqlDropTables() {
PGPASSWORD=<your password>
PGTABLE=<your table name>
PGUSER=<your pg user name>
PGPASSWORD=$PGPASSWORD psql -ah 127.0.0.1 $PGTABLE $PGUSER -c "
SELECT
'DROP TABLE IF EXISTS \"' || tablename || '\" CASCADE;' from
pg_tables WHERE schemaname = 'public';" | grep DROP | awk 'NR>1{print $0}' | sed "s/\"/'/g" | PGPASSWORD=$PGPASSWORD xargs -i psql -ah 127.0.0.1 $PGTABLE $PGUSER -c {}
}
It creates all the required drop table statements as stated in this response, replaces the " with ' and runs them on the DB.
Maybe the simplest way is:
Drop database contains that tables with:
drop database DATABASE_NAME;
Recreate that database:
create database DATABASE_NAME;
Here's the ready-made query for you:
SELECT
'drop table if exists "' || tablename || '" cascade;' as pg_drop
FROM
pg_tables
WHERE
schemaname='your schema';
for macOS. If you have a terminal via PostgreSQL application, a simple command can help you:
drop table "organisations" cascade;