执行在查询中创建的多个 SQL 个字符串

Execute multiple SQL strings created in query

我正在尝试为数据库中的(几乎)所有表动态创建审计表。我可以动态生成适当的 SQL,如下所示:

SELECT                          
    'CREATE TABLE IF NOT EXISTS '
    || tab_name || '_audit(timestamp TIMESTAMPTZ NOT NULL, entity JSONB NOT NULL);'
FROM (
    SELECT                                                                     
        quote_ident(table_schema) || '.' || quote_ident(table_name) as tab_name
    FROM                         
        information_schema.tables
    WHERE                                                       
        table_schema NOT IN ('pg_catalog', 'information_schema')
        AND table_schema NOT LIKE 'pg_toast%'
) tablist;

这给了我一系列的表格行:

CREATE TABLE IF NOT EXISTS public.table1_audit(timestamp TIMESTAMPTZ NOT NULL, entity JSONB NOT NULL);
CREATE TABLE IF NOT EXISTS public.table2_audit(timestamp TIMESTAMPTZ NOT NULL, entity JSONB NOT NULL);

等 我正在苦苦挣扎的是实际执行那些动态生成的查询。通过搜索 EXECUTE 似乎是必需的函数,但我无法在不产生语法错误或什么都不做的情况下让它工作。如果能指出正确的方向,我将不胜感激。

您可以在 DO statement:

的循环中使用动态 SQL 和 EXECUTE
DO
$$
DECLARE
   _sql text;
BEGIN
   FOR _sql IN
      SELECT format('CREATE TABLE IF NOT EXISTS %I.%I(timestamp timestamptz NOT NULL, entity jsonb NOT NULL)'
                  , schemaname
                  , tablename || '_audit')
      FROM   pg_catalog.pg_tables  -- only tables and partitioned tables, no toast tables
      WHERE  schemaname NOT IN ('pg_catalog', 'information_schema')
   LOOP
      RAISE NOTICE '%', _sql;
      -- EXECUTE _sql;
   END LOOP;
END
$$;

我先扔了一个 RAISE NOTICE 来检查负载。
取消注释 EXECUTE 行以实际执行。

quote_ident(table_name) 附加“_audit”之前。对于所有实际需要双引号的 table 名称,这将失败。你必须做 quote_ident(table_name || 'audit')。但我改用 format() 。更方便。参见:

  • Define table and column names as arguments in a plpgsql function?

我也用pg_catalog.pg_tables代替information_schema.tables。更快,正是您所需要的。参见:

  • How to check if a table exists in a given schema

我放弃了子查询 - 不需要。