如何将CSV文件中的标头从CSV文件复制到PostgreSQL表?


93

我想将CSV文件复制到Postgres表中。该表中大约有100列,因此,如果不需要,我不想重写它们。

我正在使用\copy table from 'table.csv' delimiter ',' csv;命令,但没有创建表,我得到了ERROR: relation "table" does not exist。如果我添加一个空白表,则不会出现任何错误,但是什么也不会发生。我尝试了两次或三次此命令,但没有输出或消息,但是当我通过PGAdmin检查表时,表并未更新。

有没有办法像我想要的那样导入包含标题的表?


2
您的表名为table?非常混乱。该表是否存在,或者您要基于CSV创建表?(您不能)
wildplasser

1
好吧,我给它起了别的名字,但是在这个例子中,我们称之为表。我尝试在没有它的情况下尝试也\copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;没有运气。理想情况下,可以仅通过CSV创建表,并使用该文件中的标题。
斯坦利杯Phil


2
对于打算将大型csv转换为postgres表的任何人来说,请注意-postgres在单个表中的上限为1600列。您不能将表分块为1600列大小的表,然后再将它们加入。您需要重新设计数据库。
Achekroud 2015年

如果您可以使用python,则可以使用d6tstack。它也照顾模式更改。
citynorman

Answers:


135

这工作了。第一行中有列名。

COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER

5
我认为此命令的问题在于,您必须是数据库超级用户。\复制作品作为普通用户,太
Exocom

29
COPY不会创建表或向表中添加列,它会向具有现有列的现有表中添加行。COPY至少从PG 9.3起,推定者大概想自动创建〜100列,并且不具有此功能。
DanielVérité2014年

2
@Exocom很好。因为我从来不是我使用的Postgres系统上数据库的管理员或超级用户(pgadmin使我成为我使用的数据库的所有者,并赋予了我有限的特权/角色),所以我必须使用过\ COPY。干杯
G. Cito 2014年

2
@Daniel我理解用户的表已经存在,并有他们所需要的列,他们希望简单ADD的数据。
G. Cito 2014年

获得syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADER了aws redshift。
秘银

24

使用Python库pandas,您可以轻松创建列名并从csv文件推断数据类型。

from sqlalchemy import create_engine
import pandas as pd

engine = create_engine('postgresql://user:pass@localhost/db_name')
df = pd.read_csv('/path/to/csv_file')
df.to_sql('pandas_db', engine)

所述if_exists参数可以被设置为替代或附加到现有的表,例如df.to_sql('pandas_db', engine, if_exists='replace')。这也适用于其他输入文件类型,请参见此处此处的文档。


1
我发现pd.DataFrame.from_csv给我带来的麻烦更少,但是到目前为止,此答案是执行此操作的最简单方法,IMO。
布罗克(Brock)2015年

是的,我不确定为什么输入pd.read_excel而不是pd.read_csv。我更新了答案。
joelostblom 2015年

1
当您不想预先创建将容纳大型csv的表时,这是一个绝佳的解决方案。不过请注意-postgres在一个表中只能容纳1600列。显然其他DB引擎将允许更多。拥有如此多的列显然是不良的SQL形式,尽管这种共识尚未渗透到流行病学。
Achekroud 2015年

1
默认情况下df.to_sql()非常慢,可以使用d6tstack加快速度。它也照顾模式更改。
citynorman

13

未经允许,由终端选择

NOTES上pg文档

该路径将相对于服务器进程的工作目录(通常是集群的数据目录)而不是客户端的工作目录进行解释。

因此,无论psql是在本地服务器上还是在任何客户端上使用,通常都会遇到问题...而且,如果要为其他用户表达COPY命令,例如。在Github自述文件中,读者将遇到问题...

表示具有客户权限的相对路径的唯一方法是使用STDIN

当指定STDIN或STDOUT时,数据通过客户端和服务器之间的连接进行传输。

这里记住的

psql -h remotehost -d remote_mydb -U myuser -c \
   "copy mytable (column1, column2) from STDIN with delimiter as ','" \
   < ./relative_path/file.csv

3

我使用该功能已有一段时间,没有任何问题。您只需要提供csv文件中存在的number列,它将使用第一行的标题名称并为您创建表:

create or replace function data.load_csv_file
    (
        target_table  text, -- name of the table that will be created
        csv_file_path text,
        col_count     integer
    )

    returns void

as $$

declare
    iter      integer; -- dummy integer to iterate columns with
    col       text; -- to keep column names in each iteration
    col_first text; -- first column name, e.g., top left corner on a csv file or spreadsheet

begin
    set schema 'data';

    create table temp_table ();

    -- add just enough number of columns
    for iter in 1..col_count
    loop
        execute format ('alter table temp_table add column col_%s text;', iter);
    end loop;

    -- copy the data from csv file
    execute format ('copy temp_table from %L with delimiter '','' quote ''"'' csv ', csv_file_path);

    iter := 1;
    col_first := (select col_1
                  from temp_table
                  limit 1);

    -- update the column names based on the first row which has the column names
    for col in execute format ('select unnest(string_to_array(trim(temp_table::text, ''()''), '','')) from temp_table where col_1 = %L', col_first)
    loop
        execute format ('alter table temp_table rename column col_%s to %s', iter, col);
        iter := iter + 1;
    end loop;

    -- delete the columns row // using quote_ident or %I does not work here!?
    execute format ('delete from temp_table where %s = %L', col_first, col_first);

    -- change the temp table name to the name given as parameter, if not blank
    if length (target_table) > 0 then
        execute format ('alter table temp_table rename to %I', target_table);
    end if;
end;

$$ language plpgsql;

别忘了更改set schema 'data';为适合您的情况
穆罕默德(Mohmet)

0

您可以使用d6tstack为您创建表,并且比pd.to_sql()更快,因为它使用本机数据库导入命令。它支持Postgres以及MYSQL和MS SQL。

import pandas as pd
df = pd.read_csv('table.csv')
uri_psql = 'postgresql+psycopg2://usr:pwd@localhost/db'
d6tstack.utils.pd_to_psql(df, uri_psql, 'table')

对于导入多个CSV,解决数据模式更改和/或在写入db之前用熊猫进行预处理(例如日期),它也很有用,请参阅示例笔记本中的进一步内容。

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.