在PostgreSQL中稍后将命令选择到临时表中以执行EXECUTE

时间:2015-05-17 04:58:07

标签: postgresql

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

所以最后,我希望有一个包含单个列的表,每一行都是一个命令(或一组命令,具体取决于具体情况),我认为这看起来像这样... < / p>

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';

然而,有了这个,我得到以下错误......

  

错误:语法错误在“”删除表中或附近如果存在“”dummy_table“”cascade;“”

     

第1行:(“drop table if exists”“dummy_table”“cascade;”)

我认为这是逃避字符的问题,但我不完全确定如何将其纳入A)表的填充或B)每行的执行。有谁知道我能做些什么才能达到理想的效果?

2 个答案:

答案 0 :(得分:2)

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();。您只需将任何其他内务工作添加到存储过程中。

答案 1 :(得分:0)

我在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');”。