将PostgreSQL表中的特定行导出为INSERT SQL脚本


196

我有一个名为:的数据库模式nyummy和一个名为的表cimory

create table nyummy.cimory (
  id numeric(10,0) not null,
  name character varying(60) not null,
  city character varying(50) not null,
  CONSTRAINT cimory_pkey PRIMARY KEY (id)
);

我想将cimory表的数据导出为插入SQL脚本文件。但是,我只想导出城市等于“东京”的记录/数据(假设城市数据全部为小写)。

怎么做?

解决方案是使用免费的GUI工具还是命令行都没关系(尽管GUI工具解决方案更好)。我曾经尝试过pgAdmin III,但是找不到执行此操作的选项。


2
您可以跳过INSERT语句,而直接在数据库之间使用SELECT复制。albertech.blogspot.com/2016/11/…–
jar

PostgreSQL无法跨数据库选择。至少,较旧的版本不能,Greenplum也不能,也不知道9.x。
PhilHibbs

我意识到这是旧的,但我只是想提一提,它可以跨使用数据库来选择DBLINK,因为至少V8.3已可用。它利用外部服务器和外部数据包装器连接到“远程”数据库。无论这些数据库存在于同一实例还是完全不同的主机上,这都行得通。我已经相当广泛地使用它来在其他数据库中创建物化视图,以促进某些报告等,并且效果很好。
G_Hosa_Phat

Answers:


280

使用要导出的集合创建一个表,然后使用命令行实用程序pg_dump导出到文件:

create table export_table as 
select id, name, city
from nyummy.cimory
where city = 'tokyo'
$ pg_dump --table=export_table --data-only --column-inserts my_database > data.sql

--column-inserts 将作为具有列名称的插入命令转储。

--data-only 不要转储架构。

如下所述,在需要使用新导出时,在其中创建视图而不是表将避免创建表。


3
好的,到目前为止,您的解决方案都可以使用。错过的一件事是我需要添加“ -U user_name”。我用ToraSQL工具也几乎成功,只是脚本结果中的日期时间数据有错误。如果没有人可以在2天内提供GUI工具解决方案,那么您的回答将被接受
空值

2
只想与其他人共享,您也可以使用此免费的GUI工具:SQL Workbench / J(带有postgreSQL jdbc4驱动程序)来执行相同的操作。
2012年

1
使用会更好create view export_view...,因为随着基表的更改视图将保持最新。该文件说,--table=table: Dump only tables (or **views**...所以我有一些希望这会工作,但倾倒视图黯然产生任何数据。:P
豪华的

@poshest在9.5中对我有效。您到底尝试了什么?
克洛多尔多·内图

@ClodoaldoNeto哦,好极了!我希望我也能使它工作。我使用的是pg_dump --table=my_schema.my_view --data-only --inserts my_db > data.sql9.5.3版,create除了之外,我的声明与您的相同create view...。我在输出中得到的只是通常的pg_dump注释和SET语句。不知道我要去哪里错了。
豪华的

176

对于仅数据导出,请使用COPY
您会得到一个文件,其中每行一个表行为纯文本(不是INSERT命令),它更小,更快:

COPY (SELECT * FROM nyummy.cimory WHERE city = 'tokio') TO '/path/to/file.csv';

使用以下命令将同一文件导入到具有相同结构的另一个表中:

COPY other_tbl FROM '/path/to/file.csv';

COPY写入和读取文件服务器本地的,不像在客户端程序pg_dumppsql该读写文件的本地客户端。如果两者都在同一台计算机上运行,​​那没关系,但是对于远程连接来说却没有关系。

还有\copypsql命令

执行前端(客户端)副本。这是运行SQL COPY命令的操作,但是psql读取或写入文件并在服务器和本地文件系统之间路由数据,而不是服务器读取或写入指定的文件。这意味着文件的可访问性和特权是本地用户的特权,而不是服务器的特权,并且不需要SQL超级用户特权。


10
OP专门将数据作为插入sql脚本文件进行调用。我猜他在说insert命令,不是吗?
Clodoaldo Neto 2012年

1
@Clodoaldo:您可能是对的,在这种情况下,您的答案会更好。也可以在pgAdmin中分别复制CREATE脚本(正如OP提到的GUI)。
Erwin Brandstetter,2012年

3
STDIN并且STDOUT可以代替文件路径使用,对小数据导出很有用。
阿米尔·阿里·阿克巴里

1
如果没有--column-inserts标志,pg_dump将COPY为其生成的SQL代码中的每个表使用STDIN中的表。
兰德尔(Randall)2016年

2
请注意,您选择的列的顺序与目标数据库中的列的顺序匹配。如果不是这样,这可能会失败,或者更糟,是成功但插入错误的数据。
内森·华莱士

32

这是使用pgAdmin手动将表导出到脚本简便快捷方法,无需进行额外的安装

  1. 右键单击目标表,然后选择“备份”。
  2. 选择一个文件路径来存储备份。作为格式选择“普通”。
  3. 打开底部的“转储选项#2”选项卡,然后选中“使用列插入”。
  4. 单击备份按钮。
  5. 如果使用文本阅读器(例如notepad ++)打开生成的文件,则会获得一个脚本来创建整个表。从那里,您可以简单地复制生成的INSERT语句。

此方法还可以使用制作export_table的技术,如@Clodoaldo Neto的答案所示。

在目标表上单击鼠标右键,然后选择“备份”

选择目标路径并将格式更改为“普通”

打开底部的“转储选项#2”选项卡,然后选中“使用列插入”

您可以从那里复制INSERT语句。


当我这样做时,没有“ Bakckup”选项。这是连接到Greenplum 4.3.4.1(基于PostgreSQL 8.2.15)的pgAdmin III v1.18.1。
PhilHibbs

我安装的pgAdmin III v1.18.1有 “备份”选项。我连接到PostgreSQL 9.5。因此,问题很可能出在pgAdmin和Greenplum之间。
安迪R

按照pgAdmin4的预期工作
Nikhil

9

SQL Workbench具有这样的功能。

运行查询后,右键单击查询结果,然后选择“将数据复制为SQL> SQL插入”


1
效果很好。当选择“ postgres”作为“驱动程序”时,可能必须自己下载JDBC驱动程序:jdbc.postgresql.org/download.html (这是一个.jar文件-Java二进制文件)并将其添加为PostgreSQL连接的“驱动程序”。连接字符串(或接口中的URL)应如下所示:jdbc:postgresql://127.0.0.1:5432 / db_name
mrmuggles

DBVisualizer具有类似且出色的功能,可以复制到文件或直接复制到剪贴板。
Noumenon

8

对于我的用例,我能够简单地通过管道传递给grep。

pg_dump -U user_name --data-only --column-inserts -t nyummy.cimory | grep "tokyo" > tokyo.sql

2
必须考虑在其他领域拥有“东京”。
Buyut Joko Rivai '16

@BuyutJokoRivai,因为在大多数情况下它只是一个表转储,所以应该没问题
Ismail Iqbal

在其他案例中,最巧妙的方法是<3
Nam G VU

虽然使用大表,但是您将转储grep的所有行,这是解决方案的陷阱。然后,我们查询和将结果存储到表以进行转储的方式就象这里stackoverflow.com/a/12816187/248616更加适合
Nam G VU

5

我试图编写一种基于@PhilHibbs代码的方法,以不同的方式进行。请看一下并测试。

 CREATE OR REPLACE FUNCTION dump(IN p_schema text, IN p_table text, IN p_where text)
   RETURNS setof text AS
 $BODY$
 DECLARE
     dumpquery_0 text;
     dumpquery_1 text;
     selquery text;
     selvalue text;
     valrec record;
     colrec record;
 BEGIN

     -- ------ --
     -- GLOBAL --
     --   build base INSERT
     --   build SELECT array[ ... ]
     dumpquery_0 := 'INSERT INTO ' ||  quote_ident(p_schema) || '.' || quote_ident(p_table) || '(';
     selquery    := 'SELECT array[';

     <<label0>>
     FOR colrec IN SELECT table_schema, table_name, column_name, data_type
                   FROM information_schema.columns
                   WHERE table_name = p_table and table_schema = p_schema
                   ORDER BY ordinal_position
     LOOP
         dumpquery_0 := dumpquery_0 || quote_ident(colrec.column_name) || ',';
         selquery    := selquery    || 'CAST(' || quote_ident(colrec.column_name) || ' AS TEXT),';
     END LOOP label0;

     dumpquery_0 := substring(dumpquery_0 ,1,length(dumpquery_0)-1) || ')';
     dumpquery_0 := dumpquery_0 || ' VALUES (';
     selquery    := substring(selquery    ,1,length(selquery)-1)    || '] AS MYARRAY';
     selquery    := selquery    || ' FROM ' ||quote_ident(p_schema)||'.'||quote_ident(p_table);
     selquery    := selquery    || ' WHERE '||p_where;
     -- GLOBAL --
     -- ------ --

     -- ----------- --
     -- SELECT LOOP --
     --   execute SELECT built and loop on each row
     <<label1>>
     FOR valrec IN  EXECUTE  selquery
     LOOP
         dumpquery_1 := '';
         IF not found THEN
             EXIT ;
         END IF;

         -- ----------- --
         -- LOOP ARRAY (EACH FIELDS) --
         <<label2>>
         FOREACH selvalue in ARRAY valrec.MYARRAY
         LOOP
             IF selvalue IS NULL
             THEN selvalue := 'NULL';
             ELSE selvalue := quote_literal(selvalue);
             END IF;
             dumpquery_1 := dumpquery_1 || selvalue || ',';
         END LOOP label2;
         dumpquery_1 := substring(dumpquery_1 ,1,length(dumpquery_1)-1) || ');';
         -- LOOP ARRAY (EACH FIELD) --
         -- ----------- --

         -- debug: RETURN NEXT dumpquery_0 || dumpquery_1 || ' --' || selquery;
         -- debug: RETURN NEXT selquery;
         RETURN NEXT dumpquery_0 || dumpquery_1;

     END LOOP label1 ;
     -- SELECT LOOP --
     -- ----------- --

 RETURN ;
 END
 $BODY$
   LANGUAGE plpgsql VOLATILE;

然后 :

-- for a range
SELECT dump('public', 'my_table','my_id between 123456 and 123459'); 
-- for the entire table
SELECT dump('public', 'my_table','true');

在我的postgres 9.1上进行了测试,使用的表具有混合字段数据类型(文本,双精度,整型,不带时区的时间戳等)。

这就是为什么需要TEXT类型的CAST的原因。我的测试正确运行了大约900万行,看起来好像在运行18分钟之前就失败了。

ps:我在Web上找到了mysql的等效项。



2

我只是敲了一个快速的程序来做到这一点。它仅适用于单行,因此我创建了一个临时视图,该视图仅选择所需的行,然后将pg_temp.temp_view替换为要插入的实际表。

CREATE OR REPLACE FUNCTION dv_util.gen_insert_statement(IN p_schema text, IN p_table text)
  RETURNS text AS
$BODY$
DECLARE
    selquery text; 
    valquery text; 
    selvalue text; 
    colvalue text; 
    colrec record;
BEGIN

    selquery := 'INSERT INTO ' ||  quote_ident(p_schema) || '.' || quote_ident(p_table);

    selquery := selquery || '(';

    valquery := ' VALUES (';
    FOR colrec IN SELECT table_schema, table_name, column_name, data_type
                  FROM information_schema.columns 
                  WHERE table_name = p_table and table_schema = p_schema 
                  ORDER BY ordinal_position 
    LOOP
      selquery := selquery || quote_ident(colrec.column_name) || ',';

      selvalue := 
        'SELECT CASE WHEN ' || quote_ident(colrec.column_name) || ' IS NULL' || 
                   ' THEN ''NULL''' || 
                   ' ELSE '''' || quote_literal('|| quote_ident(colrec.column_name) || ')::text || ''''' || 
                   ' END' || 
        ' FROM '||quote_ident(p_schema)||'.'||quote_ident(p_table);
      EXECUTE selvalue INTO colvalue;
      valquery := valquery || colvalue || ',';
    END LOOP;
    -- Replace the last , with a )
    selquery := substring(selquery,1,length(selquery)-1) || ')';
    valquery := substring(valquery,1,length(valquery)-1) || ')';

    selquery := selquery || valquery;

RETURN selquery;
END
$BODY$
  LANGUAGE plpgsql VOLATILE;

因此调用:

SELECT distinct dv_util.gen_insert_statement('pg_temp_' || sess_id::text,'my_data') 
from pg_stat_activity 
where procpid = pg_backend_pid()

我尚未针对注入攻击进行过测试,请告诉我quote_literal调用是否还不够。

它还仅适用于可以简单地转换为:: text并再次返回的列。

这也适用于Greenplum,但我想不出它在CMIIW的Postgres上不起作用的原因。


-2

您是否在pgadmin中尝试过执行带有 " EXECUTE QUERY WRITE RESULT TO FILE " 选项的 查询

它只导出数据,否则尝试像

pg_dump -t view_name DB_name > db.sql

-t选项用于==>仅转储与表匹配的表(或视图或序列),请参见


1
这只会导出一条create view语句
cdmckay 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.