Export specific rows from a PostgreSQL table as INSERT SQL script
我有一个名为:
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) ); |
我想将
怎么做?
解决方案是否在免费的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 |
如下所述,无论何时需要新的导出,创建视图而不是表都将避免创建表。
对于仅数据导出,请使用
你得到的文件每行有一个表行作为纯文本(不是
1 | COPY (SELECT * FROM nyummy.cimory WHERE city = 'tokio') TO '/path/to/file.csv'; |
使用以下内容将相同结构导入同一结构的另一个表:
1 | COPY other_tbl FROM '/path/to/file.csv'; |
还有psql的
Performs a frontend (client) copy. This is an operation that runs an
SQLCOPY 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手动将表导出到脚本而不需要额外安装的简单快捷的方法:
这个方法也适用于制作export_table的技术,如@Clodoaldo Neto的回答所示。
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。
你有没有尝试过使用
它只导出数据,否则尝试
1 | pg_dump -t view_name DB_name > db.sql |
-t选项用于==>仅转储表(或视图或序列)匹配表,参考