drop all tables sharing the same prefix in postgres
Asked Answered
B

3

26

I would like to delete all tables sharing the same prefix ('supenh_agk') from the same database, using one sql command/query.

Become answered 22/12, 2014 at 21:44 Comment(1)
Possible duplicate of How to drop multiple tables in PostgreSQL using a wildcardCharliecharline
N
42

To do this in one command you need dynamic SQL with EXECUTE in a DO statement (or function):

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 'prefix' || '%'  -- your table name prefix
    AND    table_schema NOT LIKE 'pg\_%'    -- exclude system schemas
LOOP
   RAISE NOTICE '%',
-- EXECUTE
  'DROP TABLE ' || _tbl;  -- see below
END LOOP;
END
$do$;

This includes tables from all schemas the current user has access to. I excluded system schemas for safety.

If you do not escape identifiers properly the code fails for any non-standard identifier that requires double-quoting.
Plus, you run the risk of allowing SQL injection. All user input must be sanitized in dynamic code - that includes identifiers potentially provided by users.

Potentially hazardous! All those tables are dropped for good. I built in a safety. Inspect the generated statements before you actually execute: comment RAISE and uncomment the EXECUTE.

If any other objects (like views etc.) depend on a table you get an informative error message instead, which cancels the whole transaction. If you are confident that all dependents can die, too, append CASCADE:

  'DROP TABLE ' || _tbl || ' CASCADE;

Closely related:

Alternatively you could build on the catalog table pg_class, which also provides the oid of the table and is faster:

...
FOR _tbl  IN
    SELECT c.oid::regclass::text  -- escape identifier and schema-qualify!
    FROM   pg_catalog.pg_class c
    JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
    WHERE  n.nspname NOT LIKE 'pg\_%'     -- exclude system schemas
    AND    c.relname LIKE 'prefix' || '%' -- your table name prefix
    AND    c.relkind = 'r'                -- only tables
...

System catalog or information schema?

How does c.oid::regclass defend against SQL injection?

Or do it all in a single DROP command. Should be a bit more efficient:

DO
$do$
BEGIN
   RAISE NOTICE '%', (
-- EXECUTE (
   SELECT 'DROP TABLE ' || string_agg(format('%I.%I', schemaname, tablename), ', ')
   --  || ' CASCADE' -- optional
   FROM   pg_catalog.pg_tables t
   WHERE  schemaname NOT LIKE 'pg\_%'     -- exclude system schemas
   AND    tablename LIKE 'prefix' || '%'  -- your table name prefix
   );
END
$do$;

Related:

Using the conveniently fitting system catalog pg_tables in the last example. And format() for convenience. See:

Nikolai answered 22/12, 2014 at 22:4 Comment(4)
Works great !! Thx Erwin.Toxoid
Hm I can actually see the DROP TABLE statements in the output, but the tables are not getting deleted. The tables are still there and containing data.. Used first version.Jacquesjacquet
@Xb74Dkjb: CASCADE has been there forever, not related to pg 12. It forces the drop including all dependent objects, which is otherwise prohibited.Nikolai
I was getting out-of-memory errors with the single DROP version. This limits the number of tables removed at once: ``` DO $do$ BEGIN EXECUTE ( SELECT 'DROP TABLE ' || string_agg(format('%I.%I', schemaname, tablename), ', ') FROM ( SELECT * FROM pg_catalog.pg_tables t WHERE schemaname NOT LIKE 'pg_%' -- exclude system schemas AND tablename LIKE 'test' || '%' -- your table name prefix LIMIT 500 ) sub ); END $do$; ```Maloy
E
16

Suppose the prefix is 'sales_'

Step 1: Get all the table names with that prefix

SELECT table_name
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE 'sales_%';

Step 2: Click the "Download as CSV" button.

Step 3: Open the file in an editor and replace "sales_ with ,sales and " with a space

Step 4: DROP TABLE sales_regist, sales_name, sales_info, sales_somthing;

Evolutionist answered 6/12, 2016 at 11:24 Comment(0)
M
4

This is sql server command, can you try this one, is it worked in postgres or not. This query wil generate the sql script for delete

SELECT 'DROP TABLE "' || TABLE_NAME || '"' 
FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_NAME LIKE '[prefix]%'

[EDIT]

begin
    for arow in
      SELECT 'DROP TABLE "' || TABLE_NAME || '"' as col1
      FROM INFORMATION_SCHEMA.TABLES 
      WHERE TABLE_NAME LIKE '[prefix]%'
    LOOP
   --RAISE NOTICE '%',    
    EXECUTE 'DROP TABLE ' || arow ;
END LOOP;
  end;
Mesmerize answered 22/12, 2014 at 21:47 Comment(4)
ok, so something like that: SELECT 'DROP TABLE ' || TABLE_NAME || ';' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'supenh_agk%'; But is there a way to execute the resultant script after it is being generated??... I want to use one command for doing it all, instead of copying the resultant code and removing the Quotes (" ") Thanks!Become
@ a_horse_with_no_name:- + is also working in sql server 2008 to concatMesmerize
+ doesn't work in postgres... (the question is around postgres). thanks! Is there a way to use 'execute' command as part of postgres query? - so to actually execute the resultant script (the output of what was suggested above)?Become
@Roy:- add this in temp table, and loop through each row to executeMesmerize

© 2022 - 2024 — McMap. All rights reserved.