如何编写从CSV文件导入数据并填充表的存储过程?

评论

为什么要使用存储过程? COPY发挥作用

我有一个上传csv文件的用户界面,为此,我需要一个实际上从cvs文件复制数据的存储过程。

您能详细说明如何使用COPY吗?

Bozhidar Batsov已经为您提供了一个示例链接,精美的手册也可能会有所帮助:postgresql.org/docs/8.4/interactive/sql-copy.html

最新手册:postgresql.org/docs/current/static/sql-copy.html

#1 楼

请看这篇简短的文章。


解决方案在这里解释为:

创建表格:

CREATE TABLE zip_codes 
(ZIP char(5), LATITUDE double precision, LONGITUDE double precision, 
CITY varchar, STATE char(2), COUNTY varchar, ZIP_CLASS varchar);


将数据从CSV文件复制到表格中:

COPY zip_codes FROM '/path/to/csv/ZIP_CODES.txt' WITH (FORMAT csv);


评论


如果您没有超级用户访问权限,则实际使用\ copy会达到相同的效果;当以非root帐户使用COPY时,它会抱怨我的Fedora 16。

–asksw0rder
2012年10月15日17:07

提示:您可以使用zip_codes(col1,col2,col3)指示CSV中包含哪些列。列的列出顺序必须与文件中出现的顺序相同。

–David Pelaez
13年1月2日,下午5:16

@ asksw0rder \ copy是否具有相同的语法? bcoz我收到\ copy语法错误

– JhovaniC
13年5月29日在19:59

我应该包括标题行吗?

–bernie2436
13-10-27在23:09

您可以轻松地添加标题行-只需在选项中添加HEADER:COPY邮政编码从'/path/to/csv/ZIP_CODES.txt'DELIMITER',CSV HEADER; postgresql.org/docs/9.1/static/sql-copy.html

–巴雷特·克拉克(Barrett Clark)
2013年11月8日15:17



#2 楼

如果您没有使用COPY(在db服务器上运行)的权限,则可以改用\copy(在db客户端中运行)。使用与Bozhidar Batsov相同的示例:

创建表:

CREATE TABLE zip_codes 
(ZIP char(5), LATITUDE double precision, LONGITUDE double precision, 
CITY varchar, STATE char(2), COUNTY varchar, ZIP_CLASS varchar);


将数据从CSV文件复制到表中:

\copy zip_codes FROM '/path/to/csv/ZIP_CODES.txt' DELIMITER ',' CSV


还可以指定要读取的列:

\copy zip_codes(ZIP,CITY,STATE) FROM '/path/to/csv/ZIP_CODES.txt' DELIMITER ',' CSV


请参阅COPY的文档:


不要将COPY与psql指令\ copy混淆。 \ copy调用COPY FROM STDIN或COPY TO STDOUT,然后将数据提取/存储在psql客户端可访问的文件中。因此,使用\ copy时,文件的可访问性和访问权限取决于客户端而不是服务器。


,并请注意:


用于标识列,COPY FROM命令将始终写入输入数据中提供的列值,例如INSERT选项OVERRIDING SYSTEM VALUE。


评论


从'/Users/files/Downloads/WOOD.TXT'DELIMITER','CSV HEADER复制投票者(ZIP,CITY);错误:最后一个预期的列之后的额外数据上下文:COPY选民,第2行:“ OH0012781511,87,26953,HOUSEHOLDER,SHERRY,LEIGH , 11/26 / 1965,08 / 19/1988,,211 N GARFIELD ST,,BLOOMD ...”

– JZ。
2015年9月6日在17:29

@JZ。我有一个类似的错误。这是因为我有多余的空白列。检查您的csv,如果您有空白列,则可能是原因。

– Alex Bennett
16年7月8日在4:32

这有点令人误解:COPY和\ copy之间的区别不仅仅是权限,而且您不能简单地添加``使其神奇地工作。请参阅此处的描述(在导出的上下文中):stackoverflow.com/a/1517692/157957

–IMSoP
17年1月26日在16:29

@IMSoP:没错,我添加了服务器和客户端的说明,以澄清

– bjelli
17年1月27日在9:03

@bjelli是\ copy比复制慢吗?我在RDS上有一个1.5MB的文件和一个db.m4.large实例,并且此复制命令已经运行了几个小时(至少3个)。

–塞巴斯蒂安
18年5月28日在22:38

#3 楼

一种快速的实现方法是使用Python pandas库(版本0.15或更高版本效果最好)。这将为您创建列-尽管显然对数据类型所做的选择可能不是您想要的。如果不能完全满足您的要求,则可以始终使用作为模板生成的“创建表”代码。

这是一个简单的示例:

 import pandas as pd
df = pd.read_csv('mypath.csv')
df.columns = [c.lower() for c in df.columns] #postgres doesn't like capitals or spaces

from sqlalchemy import create_engine
engine = create_engine('postgresql://username:password@localhost:5432/dbname')

df.to_sql("my_table_name", engine)
 


下面的代码向您展示了如何设置各种选项:

 # Set it so the raw sql output is logged
import logging
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

df.to_sql("my_table_name2", 
          engine, 
          if_exists="append",  #options are ‘fail’, ‘replace’, ‘append’, default ‘fail’
          index=False, #Do not output the index of the dataframe
          dtype={'col1': sqlalchemy.types.NUMERIC,
                 'col2': sqlalchemy.types.String}) #Datatypes should be [sqlalchemy types][1]
 


评论


此外,if_exists参数可以设置为替换或附加到现有表,例如。 df.to_sql(“ fhrs”,engine,if_exists ='replace')

– joelostblom
2015年4月30日,0:47



用户名和密码:需要创建登录名并为用户分配数据库。如果使用pgAdmin,则使用GUI创建“登录/组角色”

– Somnath Kadam
17 Mar 24 '17 at 12:52

Pandas是一种加载到sql(与csv文件)的超级慢的方式。可以慢几个数量级。

–user48956
17年5月4日在18:46

这可能是一种写入数据的方法,但是即使具有批处理和良好的计算能力,它也非常慢。使用CSV是完成此操作的好方法。

– Ankit Singh
18年7月13日在14:09

df.to_sql()确实很慢,您可以使用d6tstack中的d6tstack.utils.pd_to_psql()查看性能比较

–citynorman
18/12/4在4:07

#4 楼

这里的大多数其他解决方案要求您事先/手动创建表。在某些情况下(例如,如果目标表中有很多列),这可能不切实际。因此,以下方法可能会派上用场。

提供csv文件的路径和列数,可以使用以下函数将表加载到临时表中,该临时表将命名为target_table

顶部假定行具有列名。

create or replace function data.load_csv_file
(
    target_table text,
    csv_path text,
    col_count integer
)

returns void as $$

declare

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

begin
    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_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
    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;


评论


嗨,穆罕默德,谢谢您发布的答案,但是当我运行代码时,出现以下错误消息:错误:模式“数据”不存在

–user2867432
16年11月8日在5:34

user2867432,您需要更改相应使用的架构名称(例如,public)

–穆罕默德
16年11月8日在13:05

嗨,Mehmet,谢谢您的解决方案,它是完美的,但是仅当postgres DB用户是超级用户时才有效,有没有办法使它在没有超级用户的情况下工作?

– Geeme
17年6月23日在9:05

Geeme:在这里阅读“安全定义器”,但是我自己没有使用它。

–穆罕默德
17年6月23日在16:55

漂亮的答案!尽管在我的代码中对于他人的可读性,我不会太通用。

–Manohar Reddy Poreddy
1月15日9:33

#5 楼

您也可以使用pgAdmin,它提供了一个GUI来进行导入。这在此SO线程中显示。使用pgAdmin的优点是它也可以用于远程数据库。

与之前的解决方案非常相似,您将需要在数据库中拥有表。每个人都有自己的解决方案,但我通常要做的是在Excel中打开CSV,复制标题,将带有换位符的特殊内容粘贴到不同的工作表上,将相应的数据类型放在下一列中,然后将其复制并粘贴到文本编辑器中加上适当的SQL表创建查询,如下所示:

CREATE TABLE my_table (
    /*paste data from Excel here for example ... */
    col_1 bigint,
    col_2 bigint,
    /* ... */
    col_n bigint 
)


评论


请显示您粘贴的数据的几个示例行

–装饰
18年4月19日在11:07

#6 楼

如Paul所述,导入在pgAdmin中起作用:

右键单击表-> import

选择本地文件,格式和编码

这是一个德语pgAdmin GUI屏幕截图:



用DbVisualizer可以做类似的事情(我有许可证,不确定免费版本)

对单击表->导入表数据...



评论


DBVisualizer花了50秒的时间来导入具有三个字段的1400行-我不得不将所有内容从String投射回原本应该的样子。

–本体
16-09-29在10:46

#7 楼

COPY table_name FROM 'path/to/data.csv' DELIMITER ',' CSV HEADER;


#8 楼


首先创建一个表
然后使用复制命令复制表详细信息:

从“路径”复制表名(C1,C2,C3 ....)到您的csv文件'delimiter','csv标头;

感谢

评论


这怎么不是被接受的答案?当数据库已经有执行此命令的命令时,为什么还要编写python脚本?

– Wes
19年5月17日在4:02

#9 楼

使用此SQL代码

    copy table_name(atribute1,attribute2,attribute3...)
    from 'E:\test.csv' delimiter ',' csv header


header关键字可使DBMS知道csv文件具有带有属性的头文件

以获取更多信息,请访问http: //www.postgresqltutorial.com/import-csv-file-into-posgresql-table/

#10 楼

使用PostgreSQL的个人经验,仍在等待更快的方法。

1。如果文件存储在本地,则首先创建表框架:

    drop table if exists ur_table;
    CREATE TABLE ur_table
    (
        id serial NOT NULL,
        log_id numeric, 
        proc_code numeric,
        date timestamp,
        qty int,
        name varchar,
        price money
    );
    COPY 
        ur_table(id, log_id, proc_code, date, qty, name, price)
    FROM '\path\xxx.csv' DELIMITER ',' CSV HEADER;


2。当\ path \ xxx.csv在服务器上时,postgreSQL没有访问服务器的权限,您将必须通过内置的pgAdmin功能导入.csv文件。
< br右键单击表名,选择import。



如果仍然有问题,请参考本教程。
http://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/

#11 楼

如何将CSV文件数据导入PostgreSQL表中?

步骤:



需要在终端中连接Postgresql数据库

psql -U postgres -h localhost



需要创建数据库

create database mydb;




需要创建用户

/>
create user siva with password 'mypass';



与数据库连接

\c mydb;



需要创建模式

>
create schema trip;



需要创建表

create table trip.test(VendorID int,passenger_count int,trip_distance decimal,RatecodeID int,store_and_fwd_flag varchar,PULocationID int,DOLocationID int,payment_type decimal,fare_amount decimal,extra decimal,mta_tax decimal,tip_amount decimal,tolls_amount int,improvement_surcharge decimal,total_amount
);



将csv文件数据导入到postgresql

COPY trip.test(VendorID int,passenger_count int,trip_distance decimal,RatecodeID int,store_and_fwd_flag varchar,PULocationID int,DOLocationID int,payment_type decimal,fare_amount decimal,extra decimal,mta_tax decimal,tip_amount decimal,tolls_amount int,improvement_surcharge decimal,total_amount) FROM '/home/Documents/trip.csv' DELIMITER ',' CSV HEADER;



查找给定的表数据

select * from trip.test;




#12 楼

恕我直言,最方便的方法是使用csvkit中的csvsql遵循“将CSV数据导入到postgresql中,这是一种舒适的方法;-)”,这是一个可通过pip安装的python软件包。

评论


链接腐烂了!您链接到的文章不再有效,这使我不舒服:(

–chbrown
16年7月27日在20:18

您可能要提到他是py。

–mountainclimber11
16年8月9日在14:46

对我来说,如果尝试导入大的CSV文件,我会收到一个MemoryError消息,因此看起来好像没有流。

– DavidC
16-10-20在12:32

@DavidC有趣。您的文件有多大?你有多少内存?如果它没有按流显示,我建议在插入之前对数据进行分块

–sal
16-10-31在12:13

该文件大小为5GB,我有2GB内存。我放弃了,最后使用脚本生成CREATE TABLE和COPY命令。

– DavidC
16年11月1日在9:51

#13 楼

在Python中,您可以使用以下代码来自动创建带有列名的PostgreSQL表:

import pandas, csv

from io import StringIO
from sqlalchemy import create_engine

def psql_insert_copy(table, conn, keys, data_iter):
    dbapi_conn = conn.connection
    with dbapi_conn.cursor() as cur:
        s_buf = StringIO()
        writer = csv.writer(s_buf)
        writer.writerows(data_iter)
        s_buf.seek(0)
        columns = ', '.join('"{}"'.format(k) for k in keys)
        if table.schema:
            table_name = '{}.{}'.format(table.schema, table.name)
        else:
            table_name = table.name
        sql = 'COPY {} ({}) FROM STDIN WITH CSV'.format(table_name, columns)
        cur.copy_expert(sql=sql, file=s_buf)

engine = create_engine('postgresql://user:password@localhost:5432/my_db')

df = pandas.read_csv("my.csv")
df.to_sql('my_table', engine, schema='my_schema', method=psql_insert_copy)


它也相对较快,我可以在大约4的时间内导入超过330万行分钟。

#14 楼

您还可以使用pgfutter,或者甚至更好的pgcsv。
这些工具会根据CSV标头为您创建表格列。
pgfutter相当有问题,我建议pgcsv。
使用pgcsv的方法如下:
sudo pip install pgcsv
pgcsv --db 'postgresql://localhost/postgres?user=postgres&password=...' my_table my_file.csv


#15 楼

如果您需要从文本/解析多行CSV导入的简单机制,则可以使用:

CREATE TABLE t   -- OR INSERT INTO tab(col_names)
AS
SELECT
   t.f[1] AS col1
  ,t.f[2]::int AS col2
  ,t.f[3]::date AS col3
  ,t.f[4] AS col4
FROM (
  SELECT regexp_split_to_array(l, ',') AS f
  FROM regexp_split_to_table(
$$a,1,2016-01-01,bbb
c,2,2018-01-01,ddd
e,3,2019-01-01,eee$$, '\n') AS l) t;


DBFiddle演示

#16 楼

我创建了一个小工具,可以很容易地将csv文件导入PostgreSQL,只需一个命令,它将创建并填充表,不幸的是,此刻自动创建的所有字段都使用TEXT类型

csv2pg users.csv -d ";" -H 192.168.99.100 -U postgres -B mydatabase


该工具可以在https://github.com/eduardonunesp/csv2pg
上找到

评论


您制作了一个等效于psql -h 192.168.99.100 -U postgres mydatabase -c的单独工具-“从'users.csv'DELIMITER'复制用户;' CSV”?我猜它创建表的那部分很好,但是由于每个字段都是文本,所以它不是超级有用

– GammaGames
19-10-17在14:52



行动,谢谢大家的注意。是的,我做到了,只花了几个小时,就在Go和pq中学习了很不错的东西,在Go中学习了pq和数据库API。

–爱德华多·佩雷拉(Eduardo Pereira)
19-10-18在15:17



#17 楼

DBeaver Community Edition(dbeaver.io)使连接数据库变得很简单,然后导入CSV文件以上传到PostgreSQL数据库。它还使发布查询,检索数据以及将结果集下载为CSV,JSON,SQL或其他常见数据格式变得容易。

这是一个FOSS多平台数据库工具,适用于SQL程序员,DBA和分析人员,支持所有流行的数据库:MySQL,PostgreSQL,SQLite,Oracle,DB2,SQL Server,Sybase,MS Access,Teradata, Firebird,Hive,Presto等。它是可行的FOSS竞争对手,对于TOgre for Postgres,TOAD for SQL Server或Toad for Oracle是可行的。

我与DBeaver没有关系。我喜欢这个价格(免费!)和完整的功能,但是我希望他们能更多地打开这个DBeaver / Eclipse应用程序,并轻松地向DBeaver / Eclipse中添加分析小部件,而不是要求用户仅支付199美元的年度订阅费用直接在应用程序内创建图形和图表。我的Java编码技能很生锈,我不想花数周的时间重新学习如何构建Eclipse窗口小部件,(只是发现DBeaver可能已禁用向DBeaver Community Edition添加第三方窗口小部件的功能。)

作为Java开发人员的DBeaver高级用户能否提供一些有关创建分析小部件以添加到DBeaver社区版的步骤的见解?

评论


很高兴了解如何实际使用DBeaver导入CSV文件。无论如何,这可能会有所帮助:dbeaver.com/docs/wiki/数据传输

–umbe1987
4月17日晚上10:01

#18 楼

您可以将bash文件创建为import.sh(您的CSV格式是制表符分隔符)
 #!/usr/bin/env bash

USER="test"
DB="postgres"
TBALE_NAME="user"
CSV_DIR="$(pwd)/csv"
FILE_NAME="user.txt"

echo $(psql -d $DB -U $USER  -c "\copy $TBALE_NAME from '$CSV_DIR/$FILE_NAME' DELIMITER E'\t' csv" 2>&1 |tee /dev/tty)

 

,然后运行此文件脚本。

#19 楼

创建表,并具有用于在csv文件中创建表的必填列。


打开postgres并右键单击要加载的目标表,然后选择导入并更新“文件选项”部分中的以下步骤
现在浏览文件名的文件
以以下格式选择csv
编码为ISO_8859_5

现在转到“其他”。选项并检查标题,然后单击导入。