【问题标题】:SELECTing commands into a temp table to EXECUTE later in PostgreSQL将命令选择到临时表中以稍后在 PostgreSQL 中执行
【发布时间】:2018-08-09 04:43:43
【问题描述】:

对于我的开发人员数据库的一些花哨的数据库维护,我希望能够使用查询来生成命令来更改数据库。问题是:我是 PostgreSQL 的新手。我已经尝试过了,但失败了。

所以最后,我希望有一个单列的表,每一行都是一个命令(或一组命令,视情况而定),我认为它看起来像这样......

DO $$
DECLARE
    command_entry RECORD;
BEGIN
    FOR command_entry IN SELECT * FROM list_of_commands
    LOOP
        EXECUTE command_entry;
    END LOOP;
END;
$$;

list_of_commands 可以填充如下内容(在此示例中,它将从公共架构中删除所有表)...

CREATE TEMP TABLE list_of_commands AS
    SELECT 'drop table if exists "' || tablename || '" cascade;'
        FROM pg_tables 
        WHERE schemaname = 'public';

但是,我收到以下错误...

错误:""drop table if exists ""dummy_table"" cascade;"" 处或附近出现语法错误

LINE 1: ("drop table if exists ""dummy_table"" cascade;")

我认为这是转义字符的问题,但我不完全确定如何将其适应 A)表格的人口或 B)每行的执行。有谁知道我可以做些什么来达到预期的效果?

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    command_entry 变量是record 类型,而EXECUTE 命令需要一个字符串。显然发生的事情是 PostgreSQL 将记录转换为双引号字符串,但这会弄乱您的命令。此外,您的临时表不使用列名,使用起来有点尴尬(列名变为?column?),因此请按如下方式更改:

    CREATE TEMP TABLE list_of_commands AS
      SELECT 'drop table if exists public.' || quote_ident(tablename) || ' cascade' AS cmd
      FROM pg_tables 
      WHERE schemaname = 'public';
    
    DO $$
    DECLARE
      command_entry varchar;
    BEGIN
      FOR command_entry IN SELECT cmd FROM list_of_commands
      LOOP
        EXECUTE command_entry;
      END LOOP;
    END;
    $$;
    

    但是看到您在会话级别(临时表、匿名代码块)执行所有这些操作,为什么不编写一个存储过程来执行所有这些内务管理,当您准备好进行大扫除时呢?

    CREATE FUNCTION cleanup() RETURNS void AS $$
    BEGIN
      FOR tbl IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
      LOOP
        EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(tbl) || ' CASCADE';
      END LOOP;
    
      -- More housekeeping jobs
    END;
    $$ LANGUAGE plpgsql;
    

    这样可以节省大量输入:SELECT cleanup();。您只需添加到存储过程中即可。

    【讨论】:

    • 很好的答案!一个令人愉快的解释,装饰着一个工作代码示例,并充满了正确的(er)实践。非常感谢。
    • @JonathanPearl:另一种选择是在原始代码中使用execute immediate command_entry.cmd
    • @a_horse_with_no_name execute immediate 来自哪里?文档没有提到它。
    • 抱歉,当然只有 execute(我总是把它和 Oracle 混为一谈)
    【解决方案2】:

    Patrick 的回答有问题,所以这里是 postgreSQL 10 的更新版本。

    CREATE FUNCTION droptables(sn varchar) RETURNS void AS $$
    DECLARE
      tbl varchar;
    BEGIN
      FOR tbl IN SELECT tablename FROM pg_tables WHERE schemaname = sn
      LOOP
        EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(tbl) || ' CASCADE';
      END LOOP;
    END;
    $$ LANGUAGE plpgsql;
    

    然后是“SELECT droptables('public');”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-09
      • 2013-07-16
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 2014-10-24
      • 2020-08-01
      相关资源
      最近更新 更多