74

我有一个包含 10 列的 CSV 文件。创建具有 4 列的 PostgreSQL 表后,我想将 10 列中的一些复制到表中。

我的 CSV 表的列如下:

x1 x2 x3 x4 x5 x6 x7 x8 x9 x10

我的 PostgreSQL 表的列应该是这样的:

x2 x5 x7 x10
4

8 回答 8

88

如果是临时任务

使用输入文件中的所有列创建一个临时表

create temporary table t (x1 integer, ... , x10 text)

从文件中复制到其中:

copy t (x1, ... , x10)
from '/path/to/my_file'
with (format csv)

现在从 temp 插入最终表:

insert into my_table (x2, x5, x7, x10)
select x2, x5, x7, x10
from t

放下它:

drop table t

如果是频繁的任务

使用file_fdw扩展名。作为超级用户:

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' )
;

将 table 的 select 权限授予将要读取它的用户:

grant select on table my_csv to the_read_user;

然后在必要时直接从 csv 文件中读取,就好像它是一个表一样:

insert into my_table (x2)
select x2
from my_csv
where x1 = 2
于 2012-09-27T11:04:22.110 回答
37

You can provide the columns your want to fill with the COPY command. Like so:

\copy your_table (x2,x5,x7,x10) FROM '/path/to/your-file.csv' DELIMITER ',' CSV;

Here's the doc for the COPY command.

于 2014-08-01T00:08:57.557 回答
24

正如其他答案所指出的那样,可以指定要复制到 PG 表中的列。但是,如果没有在 CSV 中引用列名的选项,除了加载到列具有不同顺序的表中之外,它几乎没有用处。

幸运的是,从 Postgres 9.3 开始,不仅可以从文件或标准输入复制列,还可以使用 PROGRAM 从 shell 命令复制列:

程序

要执行的命令。在 COPY FROM 中,输入从命令的标准输出中读取,而在 COPY TO 中,输出被写入命令的标准输入。

请注意,该命令由 shell 调用,因此如果您需要将任何来自不受信任来源的参数传递给 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 文件,例如csvkitmiller。这是一个使用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)

于 2018-04-18T18:08:42.127 回答
15

刚到这里是为了寻求一种只加载列子集的解决方案,但显然这是不可能的。因此,使用 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

更新:

正如评论中指出的那样,上述示例都不能处理数据中的引号分隔符。换行符也是如此,因为 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。对于其他 awks,它只是一个常规变量。

于 2017-02-16T09:48:14.050 回答
5

您可以进一步采纳 James Brown 的建议,并在一行中执行所有操作:

$ awk -F ',' '{print $2","$5","$7","$10}' file | psql -d db -c "\copy MyTable from STDIN csv header"
于 2017-03-08T13:41:13.903 回答
2

如果导入的行数对您来说并不重要,您还可以:

创建两个表:

  • t1(x1 x2 x3 x4 x5 x6 x7 x8 x9 x10):包含csv文件的所有列
  • t2 (x2 x5 x7 x10):根据需要

然后创建:

  • 一个触发函数,您可以在其中将所需的列插入 t2 并返回 NULL 以防止该行被插入 t1

  • 调用此函数的 t1 (BEFORE INSERT FOR EACH ROW) 的触发器。

特别是对于较大的 csv 文件,BEFORE INSERT 触发器对于预先过滤具有某些属性的行也很有用,您也可以进行类型转换。

于 2019-03-05T11:53:25.703 回答
1

要将电子表格(Excel 或 OpenOffice Calc)中的数据加载到 postgreSQL 中:

将电子表格页面保存为 CSV 文件。首选方法是在 OpenOffice Calc 上打开电子表格并进行保存。在“导出到文本文件”窗口中,选择字符集为 Unicode (UTF8)、字段分隔符:“,”和文本分隔符“”。将显示消息说只保存活动工作表。注意:此文件必须保存在文件夹中,但不能保存在桌面上,并且必须以 UTF8 格式保存(默认的 postgreSQL 是 UTF8 编码的升级)。如果保存在桌面上,postgreSQL 将给出“拒绝访问”消息并且不会上传。

在 PostgreSQL 中,创建一个与电子表格具有相同列数的空表。

注意:在每一列上,列名必须相同,数据类型必须相同。另外,请记住字符随足够字段而变化的数据长度。

然后在 postgreSQL 上,在 SQL 窗口上,输入代码:

复制 "ABC"."def" 从 E'C:\\tmp\\blabla.csv' delimiters ',' CSV HEADER;

注意:这里 C:\\tmp 是保存 CSV 文件“blabla”的文件夹。“ABC”.“def”是在 postgreSQL 上创建的表,其中“ABC”是模式,“def”是实际表。然后按顶部的绿色按钮执行“执行查询”。当 CSV 表在每列的开头都有标题时,需要“CSV HEADER”。

如果一切正常,则不会显示错误消息,并且 CSV 文件中的表数据将被加载到 postgreSQL 表中。但如果出现错误信息,请执行以下操作:

如果错误消息表明特定列的数据太长,则增加列大小。这主要发生在字符和字符变化列上。然后再次运行“执行查询”命令。

如果错误消息表明数据类型与特定列不匹配,则更改 postgreSQL 表列上的数据类型以匹配 CSV 表中的数据类型。

在您的情况下,创建 CSV 文件后,删除不需要的列并匹配 postgre 表中的列。

于 2012-10-04T06:12:05.033 回答
-4

一种快速的方法是将表复制到本地目录是:

\copy (select * from table_name) to 'data.csv' CSV;
于 2021-03-26T13:16:39.733 回答