Как скопировать из CSV файла в таблицу PostgreSQL с заголовками в CSV файле?

Я хочу скопировать CSV файл в таблицу Postgres. В этой таблице около 100 столбцов, поэтому я не хочу их переписывать, если мне это не нужно.

Я использую команду \copy table from 'table.csv' delimiter ',' csv;, но без созданной таблицы я получаю ERROR: relation "table" does not exist. Если я добавлю пустую таблицу, я не получу ошибки, но ничего не произойдет. Я пробовал эту команду два или три раза, и не было никаких выходных или сообщений, но таблица не обновлялась, когда я проверил ее через PGAdmin.

Есть ли способ импортировать таблицу с включенными заголовками, как я пытаюсь сделать?

Ответ 1

Это сработало. В первой строке были имена столбцов.

COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER

Ответ 2

В библиотеке Python pandas вы можете легко создавать имена столбцов и выводить типы данных из файла csv.

from sqlalchemy import create_engine
import pandas as pd

engine = create_engine('postgresql://user:[email protected]/db_name')
df = pd.read_csv('/path/to/csv_file')
df.to_sql('pandas_db', engine)

Параметр if_exists может быть установлен для замены или добавления в существующую таблицу, например. df.to_sql('pandas_db', engine, if_exists='replace'). Это работает и для дополнительных типов входных файлов, docs здесь и здесь.

Ответ 3

Альтернатива терминалом без разрешения

документация pg по ПРИМЕЧАНИЯм говорят

Путь будет интерпретироваться относительно рабочего каталога процесса сервера (обычно это каталог данных кластера), а не рабочего каталога клиента.

Итак, при использовании psql или любого клиента, даже на локальном сервере, у вас есть проблемы... И, если вы выражаете команду COPY для других пользователей, например. в Github README у читателя будут проблемы...

Единственный способ выразить относительный путь с разрешениями клиента - это использование STDIN,

Когда указывается STDIN или STDOUT, данные передаются через соединение между клиентом и сервером.

как здесь > :

psql -h remotehost -d remote_mydb -U myuser -c \
   "copy mytable (column1, column2) from STDIN with delimiter as ','" \
   < ./relative_path/file.csv

Ответ 4

Я использую эту функцию некоторое время без проблем. Вам просто нужно предоставить числовые столбцы, которые есть в файле csv, и он возьмет имена заголовков из первой строки и создаст для вас таблицу:

create or replace function data.load_csv_file
    (
        target_table  text, -- name of the table that will be created
        csv_file_path text,
        col_count     integer
    )

    returns void

as $$

declare
    iter      integer; -- dummy integer to iterate columns with
    col       text; -- to keep column names in each iteration
    col_first text; -- first column name, e.g., top left corner on a csv file or spreadsheet

begin
    set schema 'data';

    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_file_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 // using quote_ident or %I does not work here!?
    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;