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

Export specific rows from a PostgreSQL table as INSERT SQL script

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

1
2
3
4
5
6
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,但我找不到这样做的选择。


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

1
2
3
4
CREATE TABLE export_table AS
SELECT id, name, city
FROM nyummy.cimory
WHERE city = 'tokyo'
1
$ pg_dump --table=export_table --data-only --column-inserts my_database > data.sql

--column-inserts将转储为带有列名的insert命令。

--data-only不转储架构。

如下所述,无论何时需要新的导出,创建视图而不是表都将避免创建表。


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

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

使用以下内容将相同结构导入同一结构的另一个表:

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

COPY写入和读取服务器本地的文件,不像客户端程序,如pg_dumppsql,它们读取和写入客户端本地的文件。如果两者都在同一台机器上运行,那么它并不重要,但它适用于远程连接。

还有psql的\copy命令:

Performs a frontend (client) copy. This is an operation that runs an
SQL COPY command, but instead of the server reading or writing the
specified file, psql reads or writes the file and routes the data
between the server and the local file system. This means that file
accessibility and privileges are those of the local user, not the
server, and no SQL superuser privileges are required.


这是一种使用pgAdmin手动将表导出到脚本而不需要额外安装的简单快捷的方法:

  • 右键单击目标表并选择"备份"。
  • 选择存储备份的文件路径。格式选择"普通"。
  • 打开底部的"转储选项#2"选项卡,然后选中"使用列插入"。
  • 单击备份按钮。
  • 如果使用文本阅读器(例如notepad ++)打开生成的文件,则会获得一个脚本来创建整个表。从那里你可以简单地复制生成的INSERT语句。
  • 这个方法也适用于制作export_table的技术,如@Clodoaldo Neto的回答所示。

    Click right on target table and choose

    Choose a destination path and change the format to

    Open the tab

    You can copy the INSERT Statements from there.


    SQL Workbench具有这样的功能。

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


    对于我的用例,我能够简单地管道grep。

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


    我尝试以不同的方式编写一个基于@PhilHibbs代码的程序。
    请看看并测试。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
     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;

    然后 :

    1
    2
    3
    4
    -- 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,double,int,没有时区的时间戳等)。

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

    ps:我在WEB上找到了mysql的等价物。


    您可以使用指定记录查看表,然后转储sql文件

    1
    2
    CREATE VIEW foo AS
    SELECT id,name,city FROM nyummy.cimory WHERE city = 'tokyo'


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    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;

    这样调用:

    1
    2
    3
    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,但我想不出为什么它不适用于Postgres,CMIIW。


    你有没有尝试过使用" EXECUTE QUERY WRITE RESULT TO FILE" 选项执行查询的pgadmin

    它只导出数据,否则尝试

    1
    pg_dump -t view_name DB_name > db.sql

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