如何从命令行删除PostgreSQL中的所有表?

我不想删除数据库本身,只想删除其中的所有表和所有数据。


当前回答

如果安装了PL/PGSQL过程语言,则可以使用以下命令删除所有内容,而无需使用shell/Perl外部脚本。

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();

我建议您将其复制到一个文件中,然后使用“--file”或“-f”选项将该文件作为输入传递给psql,而不是在“psql”提示符下键入:

psql -f clean_all_pg.sql

值得称赞的地方:我写了这个函数,但我认为这些查询(至少第一个)来自几年前pgsql邮件列表中的某个人。不记得确切的时间或哪一天。

其他回答

您可以编写一个查询来生成SQL脚本,如下所示:

select 'drop table "' || tablename || '" cascade;' from pg_tables;

Or:

select 'drop table if exists "' || tablename || '" cascade;' from pg_tables;

如果某些表由于前一句中的级联选项而自动删除。

此外,如注释中所述,您可能需要按架构名称筛选要删除的表:

select 'drop table if exists "' || tablename || '" cascade;' 
  from pg_tables
 where schemaname = 'public'; -- or any other schema

然后运行它。

光荣的COPY+PASTE也将发挥作用。

最简单的方法是删除公共模式,正如其他人在前面的答案中所建议的那样。然而,这不是一个好方法。你永远不知道对公共模式做了什么,因为它已经被遗忘,也没有被记录。你也不知道这是否会在未来发挥同样的作用。在V9中,这是很好的,但在V10中,所有用户都将失去对模式的访问,必须再次获得访问权限,否则应用程序将崩溃。我还没有检查过V11,但问题是,当你从一台机器移动到另一台机器、从一个站点移动到另个站点或从一个版本移动到另另一个版本时,你永远不知道会发生什么。如果您是有权访问数据库但不能访问模式的用户,则也无法执行此操作。

如果您需要以编程方式完成这项工作,那么上面的其他答案也涵盖了这一点,但上面的答案没有考虑到的一点是让Postgres为您完成这项任务。如果将pg_dump与-c选项一起使用,如下所示:

sudo su postgres -c "pg_dump -U postgres WhateverDB -c -f "/home/Anyone/DBBackupWhateverDB-ServerUnscheduled.sql""

这将创建一个包含sql语句的DB还原脚本,该脚本将删除所有表。

如果问这个问题的唯一目的是在还原之前删除表,那么还原将为您完成这项工作。

但是,如果您在其他方面需要它,您可以简单地从sql脚本复制drop语句。

如果您无论如何都想对所有表进行核处理,可以通过将所有表放在一个语句中来省去诸如CASCADE之类的细节。这也使执行速度更快。

SELECT 'TRUNCATE TABLE ' || string_agg('"' || tablename || '"', ', ') || ';' 
FROM pg_tables WHERE schemaname = 'public';

直接执行:

DO $$
DECLARE tablenames text;
BEGIN    
    tablenames := string_agg('"' || tablename || '"', ', ') 
        FROM pg_tables WHERE schemaname = 'public';
    EXECUTE 'TRUNCATE TABLE ' || tablenames;
END; $$

如果适用,用DROP替换TRUNCATE。

根据上面的Pablo,从一个特定的模式中删除案例:

select 'drop table "' || tablename || '" cascade;' 
from pg_tables where schemaname = 'public';

使用psql的基于终端的方法最适合我。我甚至创建了一个bash函数,因为它便于开发:

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 {}
}

它创建了此响应中所述的所有必需的放置表语句,将“替换为”并在DB上运行它们。