Як скопіювати з файлу 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
ну, я назвав це інакше, але для цього прикладу давайте назвемо це table. Я намагався з наявним і без нього, я також намагався робити \copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;без удачі. В ідеалі таблицю можна створити лише за допомогою CSV та використовувати заголовки у цьому файлі.
— Кубок Стенлі Філ


2
Це лише голова для тих, хто планує перетворити великий CSV на таблицю postgres - postgres обмежується 1600 стовпцями в одній таблиці. Ви не можете поділити таблиці на таблиці розміром 1600 колонок, а потім приєднатися до них після. Вам потрібно перепланувати db.
— Achekroud

Якщо вам доступний python, ви можете використовувати d6tstack . Він також піклується про зміни схеми.
— citynorman

Відповіді:


135

Це спрацювало. У першому рядку були назви стовпців.

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

5
Я думаю, що проблема з цією командою полягає в тому, що ви повинні бути суперкористувачем БД. \ copy працює і як звичайний користувач
— Exocom

29
COPYне створює таблицю або не додає до неї стовпці, вона додає рядки до існуючої таблиці з наявними стовпцями. Імовірно, автор запитання хоче автоматизувати створення ~ 100 стовпців і COPYне має цієї функціональності, принаймні з PG 9.3.
— Даніель Веріте

2
@Exocom хороший улов. Оскільки я ніколи не є адміністратором або суперкористувачем для БД в системах postgres, якими я користуюсь (pgadmin робить мене власником баз даних, якими я користуюся, і надає мені обмежені привілеї / ролі), я мав використовувати `\ COPY '. Вітаємо
— 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'). Це також працює для додаткових типів вхідних файлів, документи тут і тут .


1
Я вважаю, що pd.DataFrame.from_csv доставляє мені менше проблем, але ця відповідь на сьогоднішній день є найпростішим способом, IMO.
— Брок

Правда, я не впевнений, чому набрав pd.read_excel, а не pd.read_csv. Я оновив відповідь.
— joelostblom

1
це фантастичне рішення, коли ви не хочете попередньо створювати таблицю, яка міститиме великий CSV. Хоча лише на голову - postgres може приймати в таблиці лише 1600 стовпців. Очевидно, інші двигуни БД дозволять більше. Наявність такої кількості стовпців, мабуть, є поганою формою SQL, хоча цей консенсус ще не пройшов через епідеміологію.
— Achekroud

1
За замовчуванням df.to_sql()ДУЖЕ ПОВІЛЬНО, щоб пришвидшити це, ви можете використовувати d6tstack . Він також піклується про зміни схеми.
— citynorman

13

Альтернатива через термінал без дозволу

Документація пг на НОТ говорять

Шлях буде інтерпретований відносно робочого каталогу серверного процесу (як правило, каталог даних кластера), а не робочого каталогу клієнта.

Отже, загалом, за допомогою 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, вирішення змін схеми даних та / або попередньої обробки з пандами (наприклад, для дат) перед записом у db, див. Далі в прикладах зошита

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.