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

93

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

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

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

Кубок Стэнли Фил
источник
2
Ваш стол назван table? Очень запутанно. Таблица существует или вы хотите создать ее на основе CSV? (вы не можете)
wildplasser
1
ну, я назвал это как-то иначе, но для этого примера позвольте называть его таблицей. Я пробовал с его существованием и без него, тоже безуспешно пытался \copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;. В идеале таблица могла бы быть создана только с помощью CSV и использовать заголовки в этом файле.
Stanley Cup Phil
Связанный: stackoverflow.com/questions/2987433/…
G. Cito
2
Просто предупреждение для тех, кто планирует превратить большой CSV в таблицу postgres - postgres ограничен 1600 столбцами в одной таблице. Вы не можете разбить таблицы на таблицы размером 1600 столбцов, а затем присоединиться к ним. Вам нужно перепроектировать файл db.
Achekroud
Если вам доступен python, вы можете использовать d6tstack . Он также заботится об изменении схемы.
citynorman

Ответы:

135

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

COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER
G. Cito
источник
5
Я думаю, что проблема с этой командой в том, что вы должны быть суперпользователем БД. \ copy тоже работает как обычный пользователь
Exocom
29
COPYне создает таблицу и не добавляет в нее столбцы, он добавляет строки в существующую таблицу с ее существующими столбцами. Предположительно, запрашивающий хочет автоматизировать создание ~ 100 столбцов и COPYне имеет этой функции, по крайней мере, с PG 9.3.
Даниэль Верите,
2
@Exocom хороший улов. Поскольку я никогда не являюсь администратором или суперпользователем для БД в системах postgres, которые я использую (pgadmin делает меня владельцем баз данных, которые я использую, и дает мне ограниченные привилегии / роли), я, должно быть, использовал `\ COPY '. Cheers
G. Cito
2
@Daniel Я понял, что таблица пользователя уже существует, и в ней есть все столбцы, которые им нужны, и что они хотят просто ADDданные.
G. Cito
Попал syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADERна красное смещение AWS.
Mithril
24

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

from sqlalchemy import create_engine
import pandas as pd

engine = create_engine('postgresql://user:pass@localhost/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'). Это также работает для дополнительных типов входных файлов, документы здесь и здесь .

Joelostblom
источник
1
Я считаю, что pd.DataFrame.from_csv доставляет мне меньше проблем, но этот ответ, безусловно, самый простой способ сделать это, ИМО.
Brock 08
Правда, не совсем понимаю, зачем я набрал pd.read_excelвместо pd.read_csv. Я обновил ответ.
joelostblom
1
это фантастическое решение, если вы не хотите заранее создавать таблицу, которая будет содержать большой CSV. Только предупреждаем - postgres может принимать только 1600 столбцов в таблице. Видимо другие движки БД позволят больше. Наличие такого количества столбцов явно является плохой формой SQL, хотя этот консенсус еще не дошел до эпидемиологии.
Achekroud
1
По умолчанию df.to_sql()это ОЧЕНЬ МЕДЛЕННО, для ускорения вы можете использовать d6tstack . Он также заботится об изменении схемы.
citynorman
13

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

Документация 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
Питер Краусс
источник
3

Некоторое время пользуюсь этой функцией без проблем. Вам просто нужно предоставить числовые столбцы, которые есть в файле 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;
мехмет
источник
не забудьте изменить set schema 'data';к тому , что это дело для вас
Мехмет
0

Вы можете использовать d6tstack, который создает таблицу для вас и работает быстрее, чем pd.to_sql (), потому что он использует собственные команды импорта БД. Он поддерживает Postgres, а также MYSQL и MS SQL.

import pandas as pd
df = pd.read_csv('table.csv')
uri_psql = 'postgresql+psycopg2://usr:pwd@localhost/db'
d6tstack.utils.pd_to_psql(df, uri_psql, 'table')

Это также полезно для импорта нескольких CSV, решения изменений схемы данных и / или предварительной обработки с помощью pandas (например, для дат) перед записью в db, см. Далее в блокноте с примерами

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
город нормальный
источник