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

Can I automatically create a table in PostgreSQL from a csv file with headers?

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

根据这个问题,我试过了

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文档中找不到有关自动创建表的任何内容。 是否有其他方法可以自动从带有标题的CSV文件创建表格?


有一个非常好的工具可以从csv文件将表导入Postgres。
它是一个名为pgfutter的命令行工具(带有用于windows,linux等的二进制文件)。它的一大优点是它也能识别属性/列名。

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

1
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导入myTable的更精细的pgfutter示例是这样的:

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

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

1
2
3
ALTER TABLE myTable
  ALTER COLUMN myColumn TYPE NUMERIC
    USING (TRIM(myColumn)::NUMERIC)


您无法在COPY文档中找到任何内容,因为COPY无法为您创建表。
你需要在COPY之前做到这一点。


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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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文件转换为utf8
  • 1
        iconv -f ISO-8859-1 -t UTF-8 file.txt -o file.csv
  • 使用此python脚本创建sql以创建表和副本
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #!/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 ="{}
    "
    .format(';'.join(campos))

        #print(cabecalho)
        FIELDS= []
        FOR cell IN head_cells:
            FIELDS.append(" {} text".format(cell))
        TABLE = origem.split('.')[0]
        SQL ="create table {} (
     {}
    );"
    .format(origem.split('.')[0],",
    "
    .join(FIELDS))
        SQL +="
     COPY {} FROM '{}' DELIMITER ';' CSV HEADER;"
    .format(TABLE,arquivo)

        print(SQL)
        d.write(SQL)

    3.运行脚本

    1
    python3 importar.py

    可选:编辑sql脚本以调整字段类型(默认情况下都是文本)

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

    对于单个表格,我通过网络上可以找到的众多优秀转换器中的一个非常简单,快速和在线完成。
    只需谷歌将csv转换为sql在线并选择一个。