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

时间:2014-01-09 10:57:22

标签: postgresql csv

我在OS X 10.6.8上运行PostgreSQL 9.2.6。我想将带有列标题的CSV文件中的数据导入数据库。我可以使用COPY语句执行此操作,但前提是我首先手动创建一个包含CSV文件中每列的列的表。有没有办法根据CSV文件中的标题自动创建此表?

Per 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文件创建表格?

8 个答案:

答案 0 :(得分:30)

有一个非常好的工具可以从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"

pgfutter myFile导入myTable的更详细示例就是这个:

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)

答案 1 :(得分:22)

您无法在COPY文档中找到任何内容,因为COPY 无法为您创建表格。
您需要先执行此操作,然后才能COPY

答案 2 :(得分:14)

还有第二种方法,我发现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来克服了这个问题。

答案 3 :(得分:2)

我还没有使用过它,但是pgfutter开发人员推荐pgLoader(https://pgloader.io/)来解决更复杂的问题。看起来很干练。

答案 4 :(得分:1)

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

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

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

您还可以将sedcsvsql一起使用,以获取所需的数据类型:

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

答案 5 :(得分:1)

使用sqlite作为中间步骤。

步骤:

  1. 在命令提示符下,键入:sqlite3
  2. 在sqlite3 CLI中,键入:.mode csv
  3. .import my_csv.csv my_table
  4. 。输出my_table_sql.sql
  5. .dump my_table
  6. 最后在您的Postgresql中执行该sql

答案 6 :(得分:0)

对于一张桌子,我非常简单,快速且在线地通过可在网络上找到的众多转换器之一进行了在线操作。 只需在Google convert csv to sql online上选择一个即可。

答案 7 :(得分:0)

我是通过以下步骤实现的:

  1. 将csv文件转换为utf8
    iconv -f ISO-8859-1 -t UTF-8 file.txt -o file.csv
  1. 使用此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脚本以调整字段类型(默认情况下均为文本)

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