【问题标题】:Can I automatically create a table in PostgreSQL from a csv file with headers?我可以从带有标题的 csv 文件在 PostgreSQL 中自动创建一个表吗?
【发布时间】: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 文件自动创建表格?

【问题讨论】:

    标签: postgresql 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】:

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

      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" 
      

      【讨论】:

        【解决方案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 作为中间步骤。

          步骤:

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

          【讨论】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-10-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-26
            • 2019-07-21
            相关资源
            最近更新 更多