将csv文件的一些列复制到表中

POT*_*NZA 48 csv postgresql etl copy

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

我的CSV表的列如下:

x1 x2 x3 x4 x5 x6 x7 x8 x9 x10
Run Code Online (Sandbox Code Playgroud)

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

x2 x5 x7 x10
Run Code Online (Sandbox Code Playgroud)

Clo*_*eto 65

如果它是临时任务

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

create temporary table t (x1 integer, ... , x10 text)
Run Code Online (Sandbox Code Playgroud)

从文件复制到其中:

copy t (x1, ... , x10)
from '/path/to/my_file'
with (format csv)
Run Code Online (Sandbox Code Playgroud)

现在从temp插入到权威表中:

insert into my_table (x2, x5, x7, x10)
select x2, x5, x7, x10
from t
Run Code Online (Sandbox Code Playgroud)

放下它:

drop table t
Run Code Online (Sandbox Code Playgroud)

如果这是一项经常性的任务

使用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' )
;
Run Code Online (Sandbox Code Playgroud)

将表的权限授予将读取它的用户:

grant select on table my_csv to the_read_user;
Run Code Online (Sandbox Code Playgroud)

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

insert into my_table (x2)
select x2
from my_csv
where x1 = 2
Run Code Online (Sandbox Code Playgroud)

  • 是不是有更清洁的方式? (4认同)
  • 在postgreSQL 9+中使用此复制查询`COPY t(x1,...,x10)FROM'/ path/to/my_file'WITH CSV` more on [Postgresql docs](http://www.postgresql.org/文档/ 9.4 /静态/ SQL-copy.html) (4认同)
  • 哇.PostgresQL失败.即使pgadmin3中的导入命令也不允许您只是勾选要包含的CSV文件的哪些列.Sheesh,这看起来像1980年代的东西. (3认同)
  • @pratnala不,没有 (2认同)
  • @JoeStrout:PgAdmin不是Posgresql.它是Postgresql的客户端之一.使用您选择的其他客户端. (2认同)
  • 我不清楚 @juliocesar 的示例试图做什么,但根据链接的文档,“WITH CSV”是仍受支持的 9.0 之前的格式,“with (format csv)”似乎是 9.0 格式。两者似乎都不支持仅使用“COPY”查询插入列的子集。 (2认同)

Jul*_*ien 27

您可以使用COPY命令提供要填充的列.像这样:

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

这里的文档COPY命令.

  • 但是,您不能复制比文件中更少的列.使用此命令,您可以将文件的第一列复制到x2,将第二列复制到x5,依此类推,前提是文件只有4列. (37认同)
  • 如果您复制的列数据少于 CSV 文件中可用的列数据,您将收到“错误:最后一个预期列后的额外数据” (4认同)

Jam*_*own 11

刚刚到达这里寻求解决方案只加载一个列的子集,但显然这是不可能的.因此,使用awk(或cut)将所需列提取到新文件new_file:

$ awk '{print $2, $5, $7, $10}' file > new_file
Run Code Online (Sandbox Code Playgroud)

并加载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
Run Code Online (Sandbox Code Playgroud)

  • @rags 是的。通常我习惯使用 awk,因为它允许以任意顺序打印列。使用 `psql` 并不重要,因为你可以在 `\COPY` (`-c "\COPY table(col4,col3,col2,col1)..."`) 中更改表列的顺序。 (3认同)
  • cut 也支持范围,比如 _cut -d',' -f1-5,7,20 file_ 如果你有一个包含很多列的文件很有用 (2认同)

小智 8

您可以进一步采纳詹姆斯·布朗的建议并执行以下操作:

$ awk -F ',' '{print $2","$5","$7","$10}' file | psql -d db -c "\copy MyTable from STDIN csv header"
Run Code Online (Sandbox Code Playgroud)


arr*_*ond 6

正如其他答案所指出的那样,可以指定要复制到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)

  • @DerekMahar PROGRAM 允许执行涉及以编程方式操作原始 CSV 的导入操作,即全部在 Postgres 内部。当在函数内部使用以自动化导入过程时,这尤其有用。 (5认同)