Як скопіювати з файлу 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.