如何使用 CSV 文件中的标题从 CSV 文件复制到 PostgreSQL 表?
Posted
技术标签:
【中文标题】如何使用 CSV 文件中的标题从 CSV 文件复制到 PostgreSQL 表?【英文标题】:How to copy from CSV file to PostgreSQL table with headers in CSV file? 【发布时间】:2013-07-13 19:30:26 【问题描述】:我想将 CSV 文件复制到 Postgres 表。这张表大约有100列,所以如果没有必要我不想重写。
我正在使用\copy table from 'table.csv' delimiter ',' csv;
命令,但没有创建表,我得到ERROR: relation "table" does not exist
。如果我添加一个空白表,我不会收到任何错误,但没有任何反应。我尝试了这个命令两三遍,没有任何输出或消息,但是当我通过 PGAdmin 检查它时,表没有更新。
有没有办法像我尝试的那样导入包含标题的表格?
【问题讨论】:
您的表名为table
?很混乱。该表是否存在,或者您是否要基于 CSV 创建它? (你不能)
好吧,我给它起了别的名字,但在这个例子中,我们称之为表。我尝试了存在和不存在它我也尝试过\copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;
,但也没有运气。理想情况下,表格可以单独通过 CSV 创建,并使用该文件中的标题。
相关:***.com/questions/2987433/…
对于任何计划将大型 csv 转换为 postgres 表的人来说,这是一个提醒—— postgres 在单个表中的上限为 1600 列。您不能将表分块成 1600 列大小的表,然后再加入它们。您需要重新设计数据库。
如果你可以使用python,你可以使用d6tstack。它也负责架构更改。
【参考方案1】:
这行得通。第一行中有列名。
COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER
【讨论】:
我认为这个命令的问题是,你必须是数据库超级用户。 \copy 也可以作为普通用户使用COPY
不会创建表或向其中添加列,它会将行添加到现有表及其现有列。据推测,提问者希望自动创建约 100 列,而COPY
至少从 PG 9.3 开始没有此功能。
@Exocom 很好。因为我从来不是我使用的 postgres 系统上数据库的管理员或超级用户(pgadmin 使我成为我使用的数据库的所有者并给我有限的权限/角色)我必须使用 `\COPY'。干杯
@Daniel 我知道用户的表已经存在并且拥有他们需要的所有列,并且他们想要只是ADD
数据。
在 aws redshift 上获得 syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADER
。【参考方案2】:
使用 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')
。这也适用于其他输入文件类型,文档 here 和 here。
【讨论】:
我发现 pd.DataFrame.from_csv 给我带来的麻烦更少,但这个答案是迄今为止最简单的方法,IMO。 没错,我不知道为什么我输入了pd.read_excel
,而不是pd.read_csv
。我更新了答案。
当您不想预先创建将容纳大型 csv 的表时,这是一个绝妙的解决方案。不过请注意——postgres 只能在一个表中占用 1600 列。显然其他数据库引擎将允许更多。拥有这么多列显然是糟糕的 SQL 形式,尽管这种共识尚未渗透到流行病学中。
默认情况下df.to_sql()
非常慢,为了加快速度,您可以使用d6tstack。它也负责架构更改。【参考方案3】:
无权限由终端替代
pg documentation at NOTES 说
路径将被解释为相对于服务器进程的工作目录(通常是集群的数据目录),而不是客户端的工作目录。
所以,一般来说,使用psql
或任何客户端,即使在本地服务器中,您也会遇到问题......而且,如果您正在为其他用户表达 COPY 命令,例如。在 Github README 中,读者会遇到问题...
表达具有客户端权限的相对路径的唯一方法是使用STDIN,
当指定 STDIN 或 STDOUT 时,数据通过客户端和服务器之间的连接传输。
作为remembered here:
psql -h remotehost -d remote_mydb -U myuser -c \
"copy mytable (column1, column2) from STDIN with delimiter as ','" \
< ./relative_path/file.csv
【讨论】:
【参考方案4】:我已经使用这个功能一段时间了,没有任何问题。您只需要提供 csv 文件中的数字列,它将从第一行获取标题名称并为您创建表格:
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';
改成适合你的情况【参考方案5】:
您可以使用d6tstack 为您创建表,并且是faster than 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 之前使用 pandas 进行预处理(例如日期)也很有用,请参阅examples notebook 中的进一步内容
d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'),
apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
【讨论】:
以上是关于如何使用 CSV 文件中的标题从 CSV 文件复制到 PostgreSQL 表?的主要内容,如果未能解决你的问题,请参考以下文章