如何使用通配符删除 PostgreSQL 中的多个表

问题描述 投票:0回答:12

在处理分区时,经常需要一次性删除所有分区。

但是

DROP TABLE tablename*

不起作用。 (不考虑通配符)。

有没有一种优雅的(读:容易记住)方法来使用通配符在一个命令中删除多个表?

sql postgresql
12个回答
161
投票

使用逗号分隔列表:

DROP TABLE foo, bar, baz;

如果你真的需要一把步枪,这个就可以了:

CREATE OR REPLACE FUNCTION footgun(IN _schema TEXT, IN _parttionbase TEXT) 
RETURNS void 
LANGUAGE plpgsql
AS
$$
DECLARE
    row     record;
BEGIN
    FOR row IN 
        SELECT
            table_schema,
            table_name
        FROM
            information_schema.tables
        WHERE
            table_type = 'BASE TABLE'
        AND
            table_schema = _schema
        AND
            table_name ILIKE (_parttionbase || '%')
    LOOP
        EXECUTE 'DROP TABLE ' || quote_ident(row.table_schema) || '.' || quote_ident(row.table_name) || ' CASCADE ';
        RAISE INFO 'Dropped table: %', quote_ident(row.table_schema) || '.' || quote_ident(row.table_name);
    END LOOP;
END;
$$;

SELECT footgun('public', 'tablename');

33
投票

这是这个问题的另一个黑客答案。它适用于

ubuntu
,也许其他一些操作系统也适用。在 postgres 命令提示符中执行
\dt
(在我的例子中,命令提示符在
genome-terminal
内运行)。然后你会在航站楼看到很多桌子。现在使用
ctrl+click-drag
genome-terminal
功能来复制所有表的名称。 enter image description here打开 python,进行一些字符串处理(将 ' ' 替换为 '',然后 ' ' by ','),您将获得所有表的逗号分隔列表。现在在 psql shell 中执行
drop table CTRL+SHIFT+V
即可完成。我知道这太具体了,我只是想分享。 :)


24
投票

我用过这个。

echo "select 'drop table '||tablename||';' from pg_tables where tablename like 'name%'" | \
    psql -U postgres -d dbname -t | \
    psql -U postgres -d dbname

用适当的值替换

dbname
name%


17
投票

我一直觉得创建一个可以在运行之前检查和测试的 sql 脚本比依赖正确获取 plpgsql 更舒服,这样它就不会破坏我的数据库。 bash 中的一些简单操作可以从目录中选择表名,然后为我创建 drop 语句。因此,对于 8.4.x,您会得到这个基本查询:

SELECT 'drop table '||n.nspname ||'.'|| c.relname||';' as "Name" 
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','v','S','')
     AND n.nspname <> 'pg_catalog'
     AND n.nspname <> 'information_schema'
     AND n.nspname !~ '^pg_toast'
AND pg_catalog.pg_table_is_visible(c.oid);

您可以添加一个 where 子句。 (

where c.relname ilike 'bubba%'
)

输出如下所示:

         Name          
-----------------------
 drop table public.a1;
 drop table public.a2;

因此,将其保存到 .sql 文件并使用 psql -f filename.sql 运行它


10
投票

披露:这个答案适用于 Linux 用户。

我会在@prongs所说的基础上添加一些更具体的说明:

  • \dt
    可以支持通配符:因此您可以运行
    \dt myPrefix*
    例如,仅选择要删除的表;
  • 之后
    CTRL-SHIFT-DRAG
    选择然后
    CTRL-SHIFT-C
    复制文本;
  • vim
    中,转到
    INSERT MODE
    并使用
    CTRL-SHIFT-V
    ;
  • 粘贴表格
  • ESC
    ,然后运行
    :%s/[ ]*\n/, /g
    将其翻译为逗号分隔列表,然后您可以将其粘贴(不包括最后一个逗号)到
    DROP TABLE % CASCADE

5
投票

使用linux命令行工具,可以这样做:

psql -d mydb -P tuples_only=1 -c '\dt' | cut -d '|' -f 2 | paste -sd "," | sed 's/ //g' | xargs -I{} echo psql -d mydb -c "drop table {};"

注意:最后一个回显在那里,因为我找不到在 drop 命令周围添加引号的方法,因此您需要复制并粘贴输出并自己添加引号。

如果有人能解决这个小问题,那就太棒了。


1
投票

所以我今天遇到了这个问题。我通过 pgadmin3 加载我的服务器数据库并这样做。表格按字母顺序排序,因此移动并单击然后删除效果很好。


1
投票

我喜欢来自@Frank Heikens答案。感谢那。无论如何,我想改进一点;

假设我们的分区表名称是

partitioned_table
,并且我们有一个每次都会增加的数字后缀。就像
partitioned_table_00
partitioned_table_01
...
partitioned_table_99

CREATE OR REPLACE drop_old_partitioned_tables(schema_name TEXT, partitioned_table_name TEXT, suffix TEXT)
    RETURNS TEXT
    LANGUAGE plpgsql
AS
$$
DECLARE
    drop_query text;
BEGIN
    SELECT 'DROP TABLE IF EXISTS ' || string_agg(format('%I.%I', table_schema, table_name), ', ')
    INTO drop_query
    FROM information_schema.tables
    WHERE table_type = 'BASE TABLE'
      AND table_schema = schema_name
      AND table_name <= CONCAT(partitioned_table_name, '_', suffix) -- It will also drop the table which equals the given suffix
      AND table_name ~ CONCAT(partitioned_table_name, '_\d{2}');
    IF drop_query IS NULL THEN
        RETURN 'There is no table to drop!';
    ELSE
        EXECUTE drop_query;
        RETURN CONCAT('Executed query: ', (drop_query));
    END IF;
END;
$$;

对于执行,您可以运行以下代码;

SELECT drop_old_partitioned_tables('public', 'partitioned_table', '10')

顺便说明一下,如果您想对每年的表进行分区,您的表后缀应该是年份,如

partitioned_table_2021
。即使您的数据较大,无法按年进行分区,您也可以按月进行分区,如
partitioned_table_2021_01
。不要忘记根据您的需要调整您的代码。


1
投票

我参加聚会迟到了,但想与您分享另一种方法 - 使用 LATERAL join 和一个小辅助函数

CREATE OR REPLACE FUNCTION drop_table(tbl pg_tables)
  RETURNS void AS
$func$
  BEGIN
    execute 'drop table "'||tbl.tablename||'"';
  END
$func$ LANGUAGE plpgsql;

然后

select t.tablename from pg_tables t, lateral drop_table(t) where t.tablename like 'your-pattern-here';

0
投票

另一个解决方案感谢乔恩的回答:

tables=`psql -d DBNAME -P tuples_only=1 -c '\dt' |awk -F" " '/table_pattern/ {print $3","}'`
psql -d DBNAME -c "DROP TABLE ${tables%?};";

0
投票

好吧,这不是一个完整的 sql 解决方案,而是一个简单的 python 片段,您可以用它来实现您的意图。

import pandas as pd
from db import connections
from sqlalchemy.sql import text

engine = connections.pgsqlConnLifv100('your_db_name')

sql =   '''SELECT tablename FROM pg_catalog.pg_tables 
        WHERE schemaname='public'
        AND tablename LIKE 'temp_%%';'''
        
temp_tables = pd.read_sql(sql, engine)['tablename']

with engine.connect() as con:

    for table in temp_tables:
        sql = text(f"DROP table {table}")
        con.execute(sql)
        print(f"Dropped table {table}.")

0
投票

和其他人一样,我发现有时从 Python 或 R 与数据库交互很有用,因为它很容易解决在 SQL 中很复杂的多表问题(一个例子是为大的继承层次结构打开/关闭继承)。 Python 特别擅长处理文件系统。

在 R 或 Python 中,编写一个删除多个表的函数非常简单,并且它使您可以灵活地创建所需的任何表列表。我使用 PostgreSQL,所以我的 R 函数如下所示:

#Set up a connectino
library(RPostgreSQL)
drv<-dbDriver("PostgreSQL")
con <- dbConnect(drv, host="localhost",port=5432, user= "me", password="mypw",dbname="mydb")

# Define the function
batch_drop<-function(tablelist){
  for (i in 1:length(tablelist)){
    tbl<-tablelist[i]
    q<-paste("DROP TABLE",tbl)
    res <- dbSendQuery(con, q)
    print(paste("Dropped table",tbl))
  }
}

使用方法:

tablelist<-c("tbl1","tbl2",....) #make a list of tables to drop
batch_drop(tablelist) #call the function

两步过程的一个真正好处是,您可以在调用该函数之前,在闲暇时仔细检查该列表。

© www.soinside.com 2019 - 2024. All rights reserved.