ChatGPT解决这个技术问题 Extra ChatGPT

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

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

为什么是存储过程? COPY 可以解决问题
我有一个上传 csv 文件的用户界面,要连接这个我需要实际从 cvs 文件复制数据的存储过程
你能详细说明如何使用 COPY 吗?
Bozhidar Batsov 已经为您提供了一个示例链接,精美的手册也可以提供帮助:postgresql.org/docs/8.4/interactive/sql-copy.html

P
Peter Mortensen

看看这个short article

解决方案在这里解释:

创建你的表:

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。
提示:您可以使用 zip_codes(col1, col2, col3) 指明 CSV 中有哪些列。列的列出顺序必须与它们在文件中出现的顺序相同。
@asksw0rder \copy 有相同的语法吗? bcoz 我在使用 \copy 时遇到语法错误
我应该包括标题行吗?
您可以轻松地包含标题行 - 只需在选项中添加 HEADER:COPY zip_codes FROM '/path/to/csv/ZIP_CODES.txt' DELIMITER ',' CSV HEADER; postgresql.org/docs/9.1/static/sql-copy.html
P
Peter Mortensen

如果您无权使用 COPY(在 db 服务器上工作),您可以改用 \copy(在 db 客户端上工作)。使用相同的示例 as 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 ... 必须写在一行中并且没有 ;在最后!

您还可以指定要读取的列:

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

查看documentation for COPY

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

并注意:

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


\copy voters(ZIP,CITY) FROM '/Users/files/Downloads/WOOD.TXT' DELIMITER ',' CSV HEADER;错误:最后一个预期列后的额外数据上下文:复制选民,第 2 行:“OH0012781511,87,26953,HOUSEHOLDER,SHERRY,LEIGH,,11/26/1965,08/19/1988,,211 N GARFIELD ST , ,BLOOMD ……”
@JZ。我有一个类似的错误。这是因为我有额外的空白列。检查您的 csv,如果您有空白列,这可能是原因。
这有点误导:COPY\copy 之间的区别不仅仅是权限,而且您不能简单地添加一个 `` 使其神奇地工作。请参阅此处的说明(在导出的上下文中):stackoverflow.com/a/1517692/157957
@IMSoP:你说得对,我添加了对服务器和客户端的提及以澄清
@Sebastian:重要的区别是 \copy 从客户端工作。所以你仍然必须将所有数据传输到服务器。使用 COPY(无斜线),您首先使用其他方式(sftp、scp)将所有数据上传到服务器,然后在服务器上进行导入。但传输 1.5 MB 听起来并不像它应该讲 3 个小时 - 无论您采用哪种方式。
P
Peter Mortensen

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

这是一个简单的例子:

import pandas as pd
df = pd.read_csv('mypath.csv')
df.columns = [c.lower() for c in df.columns] # PostgreSQL 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

此外,if_exists 参数可以设置为替换或追加到现有表,例如 df.to_sql("fhrs", engine, if_exists='replace')
用户名和密码:需要创建登录名并将数据库分配给用户。如果使用 pgAdmin,则使用 GUI 创建“登录/组角色”
Pandas 是一种加载到 sql(相对于 csv 文件)的超慢方式。可以慢几个数量级。
这可能是一种写入数据的方式,但即使具有批处理和良好的计算能力,它也非常慢。使用 CSV 是实现此目的的好方法。
df.to_sql() 真的很慢,您可以使用 d6tstack 中的 d6tstack.utils.pd_to_psql() 参见 performance comparison
P
Peter Mortensen

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

提供 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;

嗨 Mehmet,感谢您发布的答案,但是当我运行您的代码时,我收到以下错误消息:错误:模式“数据”不存在
user2867432 您需要相应地更改您使用的架构名称(例如,public
嗨 Mehmet,感谢您的解决方案,它很完美,但这仅在 postgres DB 用户是超级用户时才有效,有没有办法让它在没有超级用户的情况下工作?
Geeme:阅读“安全定义器”here,但我自己没有使用过。
漂亮的答案!尽管在我的代码中为了其他人的可读性,我不会太笼统。
P
Peter Mortensen

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

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

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

请显示您粘贴数据的几个示例行
T
Tunaki
COPY table_name FROM 'path/to/data.csv' DELIMITER ',' CSV HEADER;

P
Peter Mortensen

作为 Paul mentioned,导入在 pgAdmin 中工作:

右键单击表格→导入

选择本地文件、格式和编码。

这是德语 pgAdmin GUI 屏幕截图:

https://i.stack.imgur.com/z9M5o.jpg

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

右键单击表→导入表数据...

https://i.stack.imgur.com/107St.jpg


DBVisualizer 花了 50 秒来导入包含三个字段的 1400 行——而且我必须将所有内容从字符串转换回它应该是的任何内容。
P
Peter Mortensen

先创建一个表然后使用复制命令复制表的详细信息:copy table_name (C1,C2,C3....) from 'path to your CSV file' delimiter ',' csv header;

笔记:

列和顺序由 SQL 中的 C1、C2、C3.. 指定

header 选项只是从输入中跳过一行,而不是根据列的名称。


这怎么不是公认的答案?当数据库已经有执行此操作的命令时,我为什么要编写 python 脚本?
P
Peter Mortensen

使用此 SQL 代码:

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

header 关键字让 DBMS 知道 CSV 文件有一个带有属性的标题。

如需更多信息,请访问 Import CSV File Into PostgreSQL Table


P
Peter Mortensen

这是个人对 PostgreSQL 的体验,我还在等待更快的方法。

如果文件存储在本地,首先创建表骨架: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);复制 ur_table(id, log_id, proc_code, date, qty, name, price) FROM '\path\xxx.csv' DELIMITER ',' CSV HEADER;当\path\xxx.csv 文件在服务器上时,PostgreSQL 没有访问服务器的权限。您必须通过 pgAdmin 内置功能导入 .csv 文件。右键单击表名并选择导入。

如果问题仍然存在,请参考本教程:Import CSV File Into PostgreSQL Table


P
Peter Mortensen

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

脚步:

需要在终端连接一个PostgreSQL数据库 psql -U postgres -h localhost 需要创建一个数据库 create database mydb;需要创建一个用户 create user siva with password 'mypass';连接数据库 \c mydb;需要创建架构创建架构行;需要创建表 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,改进附加费小数,总金额);将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,改进附加费小数,总金额) FROM '/home/Documents/trip.csv' DELIMITER ',' CSV HEADER;查找给定的表数据 select * from trip.test;


为什么我们需要复制命令的数据类型?我的意思是在第 7 步
P
Peter Mortensen

恕我直言,最方便的方法是使用 csvkit 中的 csvsql 跟随“Import CSV data into postgresql, the comfortable way ;-)”,这是一个可通过 pip 安装的 Python 包。


链接腐烂是贪婪的!您链接到的文章不再有效,这让我感到不舒服:(
你可能要提到他是 py.
对我来说,如果尝试导入大型 CSV,我会收到 MemoryError,所以它看起来好像没有流式传输。
@DavidC 有趣。你的文件有多大?你有多少内存?如果它没有像它出现的那样流式传输,我建议在插入之前对数据进行分块
该文件大小为 5GB,我有 2GB 内存。我放弃了,最后使用脚本生成 CREATE TABLE 和 COPY 命令。
P
Peter Mortensen

您也可以使用 pgfutter,或者更好的是 pgcsv

这些工具根据 CSV 标题从您那里创建表格列。

pgfutter 有很多问题,我推荐 pgcsv。

以下是使用 pgcsv 的方法:

sudo pip install pgcsv
pgcsv --db 'postgresql://localhost/postgres?user=postgres&password=...' my_table my_file.csv

P
Peter Mortensen

在 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 万行。


P
Peter Mortensen

如果文件不是很大,您可以使用 Pandas 库。

在 Pandas 数据帧上使用 iter 时要小心。我在这里这样做是为了证明这种可能性。从数据帧复制到 SQL 表时,还可以考虑使用 pd.Dataframe.to_sql() 函数。

假设您已经创建了所需的表,您可以:

import psycopg2
import pandas as pd
data=pd.read_csv(r'path\to\file.csv', delimiter=' ')

#prepare your data and keep only relevant columns

data.drop(['col2', 'col4','col5'], axis=1, inplace=True)
data.dropna(inplace=True)
print(data.iloc[:3])


conn=psycopg2.connect("dbname=db user=postgres password=password")
cur=conn.cursor()

for index,row in data.iterrows():
      cur.execute('''insert into table (col1,col3,col6)
    VALUES (%s,%s,%s)''', (row['col1'], row['col3'], row['col6'])

cur.close()
conn.commit()

conn.close()
print('\n db connection closed.')

P
Peter Mortensen

DBeaver 社区版 (dbeaver.io) 使连接数据库变得简单,然后导入 CSV 文件以上传到 PostgreSQL 数据库。它还可以轻松发出查询、检索数据以及将结果集下载为 CSV、JSON、SQL 或其他常见数据格式。

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

我与 DBeaver 没有任何关系。我喜欢它的价格(免费!)和完整的功能,但我希望他们能更多地打开这个 DBeaver/Eclipse 应用程序,让向 DBeaver/Eclipse 添加分析小部件变得容易,而不是要求用户支付 199 美元的年度订阅费直接在应用程序中创建图形和图表。我的 Java 编码技能生疏了,我不想花几周时间重新学习如何构建 Eclipse 小部件(只是发现 DBeaver 可能已经禁用了将第三方小部件添加到 DBeaver 社区版的功能。)


了解如何实际使用 DBeaver 导入 CSV 文件会很好。无论如何,这可能会有所帮助:dbeaver.com/docs/wiki/Data-transfer
彼得建议我将此问题移至评论:“作为 Java 开发人员的 DBeaver 高级用户能否提供一些有关创建分析小部件以添加到 DBeaver 社区版的步骤的见解?”我想知道分析插件是否也开源,以及如何创建它们。
P
Peter Mortensen

您可以将 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)

然后运行这个脚本。


“您的 CSV 格式是制表符分隔符”是什么意思?
D
Dharman

您有 3 个选项将 CSV 文件导入 PostgreSQL:首先,通过命令行使用 COPY 命令。

https://i.stack.imgur.com/DONA1.png

其次,使用 pgAdmin 工具的导入/导出。

https://i.stack.imgur.com/zeq8o.png

第三,使用像 Skyvia 这样的云解决方案,它可以从在线位置(如 FTP 源)或云存储(如 Google Drive)获取 CSV 文件。

https://i.stack.imgur.com/TtmaD.png

您可以查看 here 中解释所有这些的文章。


请查看Why not upload images of code/errors when asking a question?(例如,“图片应仅用于说明问题 无法以任何其他方式明确 i>例如提供用户界面的屏幕截图。)并获取相应的 action(它也包含答案)。提前致谢。
它至少适用于第一张图像。最后一张图像不可读(可能由于错误地转换为 JPEG(不适合屏幕截图)而失去保真度)。
P
Peter Mortensen

创建一个表并具有用于在 CSV 文件中创建表的所需列。

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

现在去杂项。选项。检查标题并单击导入。


P
Peter Mortensen

如果您需要一个简单的机制来从文本/解析多行 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 Demo


P
Peter Mortensen

我创建了一个小工具,可以非常轻松地将 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 "COPY users FROM 'users.csv' DELIMITER ';' CSV" 制作了一个单独的工具?我猜它创建表格的部分很好,但由于每个字段都是文本,所以它不是超级有用
操作,感谢您的提醒。是的,我做到了,而且只用了几个小时,我在 Go 和 pq 以及 Go 中的数据库 API 中学到了很酷的东西。
P
Peter Mortensen

通过使用任何客户端(我使用了 DataGrip),我创建了一个新数据库,然后在数据库的默认架构(公共)中,右键单击该数据库,然后执行 从文件导入数据

从该位置选择 CSV 文件,然后选择 Import File → Formats as TSV → 确保数据 CSV 文件的每个列名都对表的列名有所贡献。

https://i.stack.imgur.com/shg9S.png


P
Peter Mortensen

我的想法是将您的 CSV 文件转换为 SQL 查询:

打开工具 Convert CSV to Insert SQL Online 在 Data Source 窗格中粘贴或上传您的 CSV 文件 滚动到 Table Generator 面板 单击 Copy to clipboard 或 Download

例子:

id,name
1,Roberta
2,Oliver

SQL 查询的输出:

CREATE TABLE tableName
(
    id    varchar(300),
    name  varchar(300)
);

INSERT INTO tableName (id,name)
VALUES
    ('1', 'Roberta'),
    ('2', 'Oliver');