PL/pgSQL 从表中动态复制数据
PL/pgSQL to copy data from tables dynamically
我正在尝试编写一些 SQL 以根据 information_schema 中的内容从给定数据库中的所有 PostgreSQL 表复制数据。它应该将数据文件输出到我的本地机器,准备导入到另一台机器。最终,我将对此进行调整,以便我只转储 select 部分表(我转储的一些表有数百万条记录,我只需要一小部分数据用于测试目的)。
这是我目前所拥有的...
--Copy all tables...
DO
$$
DECLARE
formatstring text;
rec record;
BEGIN
RAISE NOTICE 'Copying tables...';
formatstring = 'COPY (select * from %I) to ''C:\Media\Code\%s.csv'';';
FOR rec IN
select table_name from information_schema.tables where table_schema = 'public' order by table_name
LOOP
RAISE NOTICE 'Table: %', rec.table_name;
RAISE NOTICE format(formatstring, rec.table_name, rec.table_name);
EXECUTE format(formatstring, rec.table_name, rec.table_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
但是,我遇到了这个异常...
ERROR: unrecognized exception condition "format"
CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 12
********** Error **********
ERROR: unrecognized exception condition "format"
SQL state: 42704
Context: compilation of PL/pgSQL function "inline_code_block" near line 12
单引号的转义似乎很好(已经检查过这个问题:Insert text with single quotes in PostgreSQL)。事实上,我可以执行以下操作并且它有效,文本被插入到格式中:
select format('COPY (select * from %I) to ''C:\Media\Code\%s.csv'';', 'system_user', 'system_user');
任何人都可以帮助解决这个问题吗?我可以很容易地编写一个脚本或代码来为我生成复制命令,但是如果能在 SQL.
的简单位内完成这一切就太好了
原因是您的第 3 个 RAISE
语句中存在语法错误。有 several valid formats,但不能直接将 表达式 提供给 RAISE
。它必须是字符串文字 - 带有字符串插值选项。
在此过程中,我还会简化其他一些事情:
DO
$do$
DECLARE
_formatstring text := $$COPY %1$I TO 'C:\Media\Code\%1$s.csv'$$;
_sql text;
_tbl text;
BEGIN
RAISE NOTICE 'Copying tables...';
FOR _tbl IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name
LOOP
_sql := format(_formatstring, _tbl);
RAISE NOTICE 'Table: %', _tbl;
RAISE NOTICE '%', _sql; -- fixed!!
EXECUTE _sql;
END LOOP;
END
$do$ LANGUAGE plpgsql;
要点
- 带有
COPY
而不是 SELECT * FROM tbl
的纯 table 名称。
- 嵌套的使用dollar-quotes。
- 格式说明符
%1$I
and %1$s
for the format()
函数,所以我们只需要提供一次table名称。
- 您可以在声明时分配变量。
- 标量变量而不是
FOR
循环中的 record
- 无论如何我们只需要一列。
我正在尝试编写一些 SQL 以根据 information_schema 中的内容从给定数据库中的所有 PostgreSQL 表复制数据。它应该将数据文件输出到我的本地机器,准备导入到另一台机器。最终,我将对此进行调整,以便我只转储 select 部分表(我转储的一些表有数百万条记录,我只需要一小部分数据用于测试目的)。
这是我目前所拥有的...
--Copy all tables...
DO
$$
DECLARE
formatstring text;
rec record;
BEGIN
RAISE NOTICE 'Copying tables...';
formatstring = 'COPY (select * from %I) to ''C:\Media\Code\%s.csv'';';
FOR rec IN
select table_name from information_schema.tables where table_schema = 'public' order by table_name
LOOP
RAISE NOTICE 'Table: %', rec.table_name;
RAISE NOTICE format(formatstring, rec.table_name, rec.table_name);
EXECUTE format(formatstring, rec.table_name, rec.table_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
但是,我遇到了这个异常...
ERROR: unrecognized exception condition "format" CONTEXT: compilation of PL/pgSQL function "inline_code_block" near line 12 ********** Error ********** ERROR: unrecognized exception condition "format" SQL state: 42704 Context: compilation of PL/pgSQL function "inline_code_block" near line 12
单引号的转义似乎很好(已经检查过这个问题:Insert text with single quotes in PostgreSQL)。事实上,我可以执行以下操作并且它有效,文本被插入到格式中:
select format('COPY (select * from %I) to ''C:\Media\Code\%s.csv'';', 'system_user', 'system_user');
任何人都可以帮助解决这个问题吗?我可以很容易地编写一个脚本或代码来为我生成复制命令,但是如果能在 SQL.
的简单位内完成这一切就太好了原因是您的第 3 个 RAISE
语句中存在语法错误。有 several valid formats,但不能直接将 表达式 提供给 RAISE
。它必须是字符串文字 - 带有字符串插值选项。
在此过程中,我还会简化其他一些事情:
DO
$do$
DECLARE
_formatstring text := $$COPY %1$I TO 'C:\Media\Code\%1$s.csv'$$;
_sql text;
_tbl text;
BEGIN
RAISE NOTICE 'Copying tables...';
FOR _tbl IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name
LOOP
_sql := format(_formatstring, _tbl);
RAISE NOTICE 'Table: %', _tbl;
RAISE NOTICE '%', _sql; -- fixed!!
EXECUTE _sql;
END LOOP;
END
$do$ LANGUAGE plpgsql;
要点
- 带有
COPY
而不是SELECT * FROM tbl
的纯 table 名称。 - 嵌套的使用dollar-quotes。
- 格式说明符
%1$I
and%1$s
for theformat()
函数,所以我们只需要提供一次table名称。 - 您可以在声明时分配变量。
- 标量变量而不是
FOR
循环中的record
- 无论如何我们只需要一列。