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

时间:2012-09-27 09:29:40

标签: postgresql csv copy etl

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

我的CSV表格的列如下:

x1 x2 x3 x4 x5 x6 x7 x8 x9 x10

我的PostgreSQL表的列应该是:

x2 x5 x7 x10

8 个答案:

答案 0 :(得分:58)

如果是临时任务

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

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 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

答案 1 :(得分:26)

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

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

Here's the doc用于COPY命令。

答案 2 :(得分:8)

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

答案 3 :(得分:4)

As other answers have pointed out, it's been possible to specify columns to copy into the PG table. However, without the option to reference column names in the CSV, this had little utility apart from loading into a table where columns had a different order.

Fortunately, as of Postgres 9.3, it's possible to copy columns not only from a file or from standard input, but also from a shell command using PROGRAM:

PROGRAM

A command to execute. In COPY FROM, the input is read from standard output of the command, and in COPY TO, the output is written to the standard input of the command.

Note that the command is invoked by the shell, so if you need to pass any arguments to shell command that come from an untrusted source, you must be careful to strip or escape any special characters that might have a special meaning for the shell. For security reasons, it is best to use a fixed command string, or at least avoid passing any user input in it.

This was the missing piece that we needed for such an eagerly awaited functionality. For example, we could use this option in combination with cut (in a UNIX-based system) to select certain columns by order:

COPY my_table (x2, x5, x7, x10) FROM PROGRAM 'cut -d "," -f 2,5,7,10 /path/to/file.csv' WITH (FORMAT CSV, HEADER)

However, cut has several limitations when manipulating CSV's: it can't adequately manipulate strings with commas (or other delimeters) inside them and doesn't allow to select columns by name.

There are several other open source command-line tools that are better at manipulating CSV files, such as csvkit or miller. Here's an example using miller to select columns by name:

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)

答案 4 :(得分:0)

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

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

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

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

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

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

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

如果everythig没问题,则不会显示任何错误消息,CSV文件中的表数据将被加载到postgreSQL表中。但如果出现错误消息,请执行以下操作:

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

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

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

答案 5 :(得分:0)

你可以进一步采取詹姆斯·布朗的建议,并且一行一行:

cat file | awk -F',' ' {print $ 2"," $ 5"," $ 7"," $ 10}' | psql -d db -c" \从STDIN csv header复制MyTable"

答案 6 :(得分:0)

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

创建两个表:

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

然后创建:

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

  • t1的触发器(在插入每个行之前),调用该函数。

特别是对于较大的csv文件,在INSERT触发器之前,该方法还可用于预先过滤出具有某些属性的行,并且您也可以进行类型转换。

答案 7 :(得分:-1)

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

\copy (select * from table_name) to 'data.csv' CSV;