执行在查询中创建的多个 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
我放弃了子查询 - 不需要。
我正在尝试为数据库中的(几乎)所有表动态创建审计表。我可以动态生成适当的 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:
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
我放弃了子查询 - 不需要。