我可以从带有标题的 csv 文件在 PostgreSQL 中自动创建一个表吗?

Posted

技术标签:

【中文标题】我可以从带有标题的 csv 文件在 PostgreSQL 中自动创建一个表吗?【英文标题】:Can I automatically create a table in PostgreSQL from a csv file with headers? 【发布时间】:2014-01-27 21:18:33 【问题描述】:

我在 OS X 10.6.8 上运行 PostgreSQL 9.2.6。我想将带有列标题的 CSV 文件中的数据导入数据库。我可以使用COPY 语句来做到这一点,但前提是我首先手动创建一个表,其中包含 CSV 文件中的每一列的列。有什么方法可以根据 CSV 文件中的表头自动创建这个表?

每个this question我都试过了

COPY test FROM '/path/to/test.csv' CSV HEADER;

但我只是得到这个错误:

ERROR: relation "test" does not exist

如果我首先创建一个没有列的表:

CREATE TABLE test ();

我明白了:

ERROR: extra data after last expected column

我在 PostgreSQL COPY documentation 中找不到任何关于自动创建表的信息。有没有其他方法可以从带有标题的 CSV 文件自动创建表格?

【问题讨论】:

【参考方案1】:

您在 COPY 文档中找不到任何内容,因为 COPY 无法为您创建表。 你需要这样做才能COPY

【讨论】:

这个答案其实并没有回答他的问题? 这个答案应该是评论,不能被接受,因为它没有回答问题。【参考方案2】:

有一个非常好的工具可以将表格从 csv 文件导入 Postgres。 它是一个名为 pgfutter (with binaries for windows, linux, etc.) 的命令行工具。它的一大优点是它也可以识别属性/列名称。

该工具的使用很简单。例如,如果您想导入myCSVfile.csv

pgfutter --db "myDatabase" --port "5432" --user "postgres" --pw "mySecretPassword" csv myCSVfile.csv

这将创建一个表(称为myCSVfile),其中列名取自 csv 文件的标题。此外,将从现有数据中识别数据类型。

一些注意事项:命令pgfutter 取决于您使用的二进制文件,例如它可能是pgfutter_windows_amd64.exe(如果您打算经常使用此命令,请重命名)。上述命令必须在命令行窗口中执行(例如,在 Windows 中运行 cmd 并确保 pgfutter 可访问)。如果您想使用不同的表名,请添加--table "myTable";选择一个特定的数据库模式我们--schema "mySchema"。如果您正在访问外部数据库,请使用--host "myHostDomain"

myFile 导入myTablepgfutter 的更详细示例是这个:

pgfutter --host "localhost" --port "5432" --db "myDB" --schema "public" --table "myTable" --user "postgres" --pw "myPwd" csv myFile.csv

您很可能会在导入后更改一些数据类型(从文本到数字):

alter table myTable
  alter column myColumn type numeric
    using (trim(myColumn)::numeric)

【讨论】:

如果我指定模式名称,我需要创建目标表和列。令人沮丧 当您尝试导入 CSV 文件时,此工具目前因“索引超出范围”异常而失败。 没有更改分隔符的选项。 :-( 看来您现在可以更改分隔符,例如使用制表符:pgfutter csv -d $'\t' traffic_violations.csv 目前这个应用程序在 CentOS 8 下对我“正常工作”。【参考方案3】:

还有第二种方法,我找到了here(来自 mmatt)。基本上你在 Postgres 中调用一个函数(最后一个参数指定列数)。

select load_csv_file('myTable','C:/MyPath/MyFile.csv',24)

这里是 mmatt 的功能代码,我不得不稍微修改一下,因为我正在处理公共模式。 (复制并粘贴到 PgAdmin SQL 编辑器并运行它以创建函数)

CREATE OR REPLACE FUNCTION load_csv_file(
    target_table text,
    csv_path text,
    col_count integer)
  RETURNS void AS
$BODY$

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
    set schema 'public';

    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;

$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION load_csv_file(text, text, integer)
  OWNER TO postgres;

注意:导入与编码相关的文本文件存在一个常见问题。 csv 文件应为 UTF-8 格式。但是,有时尝试进行编码的程序并不能完全实现这一点。我通过在 Notepad++ 中打开文件并将其转换为 ANSI 并转换回 UTF8 解决了这个问题。

【讨论】:

这是一个整洁的解决方案。注意确保所有列都没有保留关键字名称 - 例如,如果 CSV 文件有一个名为 order 的列(例如订单号),请将其更改为 order_num。另外,请记住根据需要更改列TYPE 此解决方案失败,因为它尝试在服务器中打开 CSV 文件,而不是在客户端中。您需要访问服务器的文件系统才能使这样的事情起作用。 我们如何让它使用本地机器上的 CSV 文件?我相信它正在寻找服务器上的文件。错误:必须是超级用户或 pg_read_server_files 角色的成员才能从文件复制提示:任何人都可以复制到标准输出或标准输入。 psql 的 \copy 命令也适用于任何人。【参考方案4】:

对于单个表,我通过网络上可以找到的众多优秀转换器之一进行了非常简单、快速和在线的操作。 只需谷歌convert csv to sql online 并选择一个。

【讨论】:

【参考方案5】:

我通过以下步骤实现了它:

    将 csv 文件转换为 utf8
    iconv -f ISO-8859-1 -t UTF-8 file.txt -o file.csv
    使用这个python脚本创建sql来创建表和复制
#!/usr/bin/env python3
import csv, os
#pip install python-slugify
from slugify import slugify

origem = 'file.csv'
destino = 'file.sql'
arquivo = os.path.abspath(origem)

d = open(destino,'w')
with open(origem,'r') as f:

    header = f.readline().split(';')
    head_cells = []
    for cell in header:
        value = slugify(cell,separator="_")
        if value in head_cells:
            value = value+'_2'
        head_cells.append(value)
    #cabecalho = "\n".format(';'.join(campos))

    #print(cabecalho)
    fields= []
    for cell in head_cells:
        fields.append("  text".format(cell))
    table = origem.split('.')[0]
    sql = "create table  ( \n  \n);".format(origem.split('.')[0],",\n".join(fields))
    sql += "\n COPY  FROM '' DELIMITER ';' CSV HEADER;".format(table,arquivo)

    print(sql)
    d.write(sql)

3.运行脚本

python3 importar.py

可选:编辑sql脚本调整字段类型(默认均为文本)

    运行 sql 脚本。控制台的缩写
sudo -H -u postgres bash -c "psql mydatabase < file.sql" 

【讨论】:

【参考方案6】:

我正在使用csvsql生成表格布局(它会自动猜测格式):

head -n 20 table.csv | csvsql --no-constraints --tables table_name 

然后我在psql 中使用\COPY。这对我来说是导入 CSV 文件的最快方法。

您还可以使用sedcsvsql 以获得所需的数据类型:

head -n 20 table.csv | csvsql --no-constraints --tables table_name  | sed 's/DECIMAL/NUMERIC/' | sed 's/VARCHAR/TEXT/'

【讨论】:

【参考方案7】:

我没用过,但是 pgfutter 开发者推荐 pgLoader (https://pgloader.io/) 来解决更复杂的问题(见上面的答案)。看起来很能干。

【讨论】:

我尝试使用它,但找不到一种方法让它为您创建一个带有 csv 输入的表。 (看来还是需要写create table语句) 是的,它看起来像you're right,它需要create table 语句;我没有注意到这一点。我想主要用于更复杂的情况,例如加载期间的动态转换。【参考方案8】:

使用 sqlite 作为中间步骤。

步骤:

    在命令提示符下输入:sqlite3 在 sqlite3 CLI 中输入:.mode csv .import my_csv.csv my_table .output my_table_sql.sql .dump my_table 最后在你的 Postgresql 中执行那个 sql

【讨论】:

TIL sqlite 有很好的导入工具!谢谢这对我很有用。【参考方案9】:

您可以使用 CSV 在DBeaver 中创建一个新表。

【讨论】:

以上是关于我可以从带有标题的 csv 文件在 PostgreSQL 中自动创建一个表吗?的主要内容,如果未能解决你的问题,请参考以下文章

postgre 导出单表和导入

WooCommerce:从 CSV 文件中删除带有 id 列表的产品 [关闭]

用于从 CSV 中删除带有特定单词的行的批处理文件

从带有标题的 CSV 文件创建表

从 html 表单发送带有 csv 附件的电子邮件

Redshift COPY 从带有 JSON 字段的 CSV 文件到 SUPER 列