【发布时间】:2012-09-19 01:16:31
【问题描述】:
我有一个包含 10 列的 CSV 文件。创建一个 4 列的 PostgreSQL 表后,我想将 10 列中的一些复制到表中。
我的 CSV 表的列如下:
x1 x2 x3 x4 x5 x6 x7 x8 x9 x10
我的 PostgreSQL 表的列应该是这样的:
x2 x5 x7 x10
【问题讨论】:
标签: postgresql
我有一个包含 10 列的 CSV 文件。创建一个 4 列的 PostgreSQL 表后,我想将 10 列中的一些复制到表中。
我的 CSV 表的列如下:
x1 x2 x3 x4 x5 x6 x7 x8 x9 x10
我的 PostgreSQL 表的列应该是这样的:
x2 x5 x7 x10
【问题讨论】:
标签: postgresql
用输入文件中的所有列创建一个临时表
create temporary table t (x1 integer, ... , x10 text)
从文件中复制到其中:
copy t (x1, ... , x10)
from '/path/to/my_file'
with (format csv)
现在从临时表中插入最终表:
insert into my_table (x2, x5, x7, x10)
select x2, x5, x7, x10
from t
然后放下它:
drop table t
使用file_fdw extension。作为超级用户:
create extension file_fdw;
create server my_csv foreign data wrapper file_fdw;
create foreign table my_csv (
x1 integer,
x2 text,
x3 text
) server my_csv
options (filename '/tmp/my_csv.csv', format 'csv' )
;
将表的选择权限授予将要读取它的用户:
grant select on table my_csv to the_read_user;
然后在必要时直接从 csv 文件中读取,就好像它是一个表格一样:
insert into my_table (x2)
select x2
from my_csv
where x1 = 2
【讨论】:
COPY t (x1, ... , x10) FROM '/path/to/my_file' WITH CSV 上使用此功能,Postgresql docs 上的更多信息
您可以使用COPY 命令提供要填充的列。像这样:
\copy your_table (x2,x5,x7,x10) FROM '/path/to/your-file.csv' DELIMITER ',' CSV;
Here's the doc 用于COPY 命令。
【讨论】:
正如其他答案所指出的,可以指定要复制到 PG 表中的列。但是,如果没有在 CSV 中引用列名的选项,除了加载到列具有不同顺序的表中之外,这几乎没有什么用处。
幸运的是,从 Postgres 9.3 开始,不仅可以从文件或标准输入复制列,还可以使用 PROGRAM 从 shell 命令复制列:
程序
要执行的命令。在 COPY FROM 中,输入从命令的标准输出中读取,而在 COPY TO 中,输出写入到命令的标准输入中。
请注意,该命令是由 shell 调用的,因此如果您需要将任何来自不可信来源的参数传递给 shell 命令,您必须小心去除或转义任何可能具有特殊含义的特殊字符对外壳的意义。出于安全原因,最好使用固定的命令字符串,或者至少避免在其中传递任何用户输入。
这是我们急需的功能所需的缺失部分。例如,我们可以将此选项与cut(在基于 UNIX 的系统中)结合使用来按顺序选择某些列:
COPY my_table (x2, x5, x7, x10) FROM PROGRAM 'cut -d "," -f 2,5,7,10 /path/to/file.csv' WITH (FORMAT CSV, HEADER)
但是,cut 在处理 CSV 时有几个限制:它无法充分处理带有逗号(或其他分隔符)的字符串,并且不允许按名称选择列。
还有其他几个更擅长处理 CSV 文件的开源命令行工具,例如 csvkit 或 miller。下面是一个使用miller 按名称选择列的示例:
COPY my_table (x2, x5, x7, x10) FROM PROGRAM 'mlr --csv lf cut -f x2,x5,x7,x10 /path/to/file.csv' WITH (FORMAT CSV, HEADER)
【讨论】:
PROGRAM 的缺失如何阻止您使用 csvkit 或 Miller 从原始 CSV 文件中选择列的子集,将它们写入新的 CSV 文件,然后仅将这些列导入该表使用\copy?
刚到这里是为了寻求一种只加载列子集的解决方案,但显然这是不可能的。因此,使用 awk(或 cut)将所需列提取到新文件 new_file:
$ awk '{print $2, $5, $7, $10}' file > new_file
并加载new_file。您可以将输出直接传送到psql:
$ cut -d \ -f 2,5,7,10 file |
psql -h host -U user -c "COPY table(col1,col2,col3,col4) FROM STDIN DELIMITER ' '" database
注意COPY,而不是\COPY。
更新:
正如 cmets 中所指出的,上述示例都不能处理数据中的引号分隔符。换行符也是如此,因为 awk 或 cut 不支持 CSV。不过,可以使用 GNU awk 处理带引号的分隔符。
这是一个三栏文件:
$ cat file
1,"2,3",4
使用 GNU awk 的 FPAT 变量,即使引用的字段中有字段分隔符,我们也可以更改字段的顺序(或获取它们的子集):
$ gawk 'BEGIN{FPAT="([^,]*)|(\"[^\"]+\")";OFS=","}{print $2,$1,$3}' file
"2,3",1,4
解释:
$ gawk '
BEGIN { # instead of field separator FS
FPAT="([^,]*)|(\"[^\"]+\")" # ... we define field pattern FPAT
OFS="," # output field separator OFS
}
{
print $2,$1,$3 # change field order
# print $2 # or get a subset of fields
}' file
请注意,FPAT 仅是 GNU awk。对于其他 awk,它只是一个常规变量。
【讨论】:
psql 没关系,因为您可以更改\COPY (-c "\COPY table(col4,col3,col2,col1)...") 中表列的顺序。
cut 和 awk not 都会给出预期的结果!使用简单工具解析 CSV 可能有效,但仅适用于简单情况。
cut 不支持 CSV。我将添加一个关于如何使用 GNU awk 处理带引号的逗号的示例。
您可以进一步采纳 James Brown 的建议,并做到这一点:
$ awk -F ',' '{print $2","$5","$7","$10}' file | psql -d db -c "\copy MyTable from STDIN csv header"
【讨论】:
如果导入的行数对您来说并不重要,您还可以:
创建两个表:
然后创建:
一个触发函数,您可以在其中将所需的列插入到 t2 中,并返回 NULL 以防止该行被插入到 t1 中
调用此函数的 t1 触发器(每行插入前)。
尤其是对于较大的 csv 文件,BEFORE INSERT 触发器也可用于预先过滤具有某些属性的行,并且您也可以进行类型转换。
【讨论】:
要将数据从电子表格(Excel 或 OpenOffice Calc)加载到 postgreSQL:
将电子表格页面保存为 CSV 文件。首选方法是在 OpenOffice Calc 上打开电子表格并进行保存。在“导出到文本文件”窗口中,选择字符集为 Unicode (UTF8)、字段分隔符:“,”和文本分隔符““”。将显示消息说只保存活动工作表。注意:此文件必须保存在文件夹中,但不能保存在桌面上,并且必须以 UTF8 格式保存(默认的 postgreSQL 是 UTF8 编码的升级)。如果保存在桌面上,postgreSQL 将给出“拒绝访问”消息并且不会上传。
在 PostgreSQL 中,创建一个与电子表格列数相同的空表。
注意:在每一列上,列名必须相同,数据类型必须相同。另外,请记住字符随足够字段而变化的数据长度。
然后在 postgreSQL 上,在 SQL 窗口中,输入代码:
从 E'C:\\tmp\\blabla.csv' 中复制 "ABC"."def" delimiters ',' CSV HEADER;
注意:这里 C:\\tmp 是保存 CSV 文件“blabla”的文件夹。 “ABC”.“def”是在 postgreSQL 上创建的表,其中“ABC”是模式,“def”是实际表。然后按顶部的绿色按钮执行“执行查询”。当 CSV 表格在每列的开头都有标题时,需要“CSV HEADER”。
如果一切正常,将不会显示错误消息,并且 CSV 文件中的表数据将被加载到 postgreSQL 表中。但是如果出现错误信息,请执行以下操作:
如果错误消息表明特定列的数据太长,则增加列大小。这主要发生在字符和字符变化列上。然后再次运行“执行查询”命令。
如果错误消息表明数据类型与特定列不匹配,则更改 postgreSQL table-column 上的数据类型以匹配 CSV 表中的数据类型。
在您的情况下,创建 CSV 文件后,删除不需要的列并匹配 postgre 表中的列。
【讨论】:
一种快速的方法是将表复制到本地目录是:
\copy (select * from table_name) to 'data.csv' CSV;
【讨论】: