在处理分区时,经常需要一次性删除所有分区。
但是
DROP TABLE tablename*
不起作用。 (不考虑通配符)。
有没有一种优雅的(读:容易记住)方法来使用通配符在一个命令中删除多个表?
使用逗号分隔列表:
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');
这是这个问题的另一个黑客答案。它适用于
ubuntu
,也许其他一些操作系统也适用。在 postgres 命令提示符中执行 \dt
(在我的例子中,命令提示符在 genome-terminal
内运行)。然后你会在航站楼看到很多桌子。现在使用 ctrl+click-drag
的 genome-terminal
功能来复制所有表的名称。 打开 python,进行一些字符串处理(将 ' ' 替换为 '',然后 '
' by ','),您将获得所有表的逗号分隔列表。现在在 psql shell 中执行 drop table CTRL+SHIFT+V
即可完成。我知道这太具体了,我只是想分享。 :)
我用过这个。
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%
。
我一直觉得创建一个可以在运行之前检查和测试的 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 运行它
披露:这个答案适用于 Linux 用户。
我会在@prongs所说的基础上添加一些更具体的说明:
\dt
可以支持通配符:因此您可以运行 \dt myPrefix*
例如,仅选择要删除的表;CTRL-SHIFT-DRAG
选择然后 CTRL-SHIFT-C
复制文本;vim
中,转到 INSERT MODE
并使用 CTRL-SHIFT-V
;ESC
,然后运行 :%s/[ ]*\n/, /g
将其翻译为逗号分隔列表,然后您可以将其粘贴(不包括最后一个逗号)到 DROP TABLE % CASCADE
。使用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 命令周围添加引号的方法,因此您需要复制并粘贴输出并自己添加引号。
如果有人能解决这个小问题,那就太棒了。
所以我今天遇到了这个问题。我通过 pgadmin3 加载我的服务器数据库并这样做。表格按字母顺序排序,因此移动并单击然后删除效果很好。
我喜欢来自@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
。不要忘记根据您的需要调整您的代码。
我参加聚会迟到了,但想与您分享另一种方法 - 使用 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';
另一个解决方案感谢乔恩的回答:
tables=`psql -d DBNAME -P tuples_only=1 -c '\dt' |awk -F" " '/table_pattern/ {print $3","}'`
psql -d DBNAME -c "DROP TABLE ${tables%?};";
好吧,这不是一个完整的 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}.")
和其他人一样,我发现有时从 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
两步过程的一个真正好处是,您可以在调用该函数之前,在闲暇时仔细检查该列表。