Bagaimana cara menyalin dari file CSV ke tabel PostgreSQL dengan header di file CSV?

93

Saya ingin menyalin file CSV ke tabel Postgres. Ada sekitar 100 kolom dalam tabel ini, jadi saya tidak ingin menulis ulang jika tidak perlu.

Saya menggunakan \copy table from 'table.csv' delimiter ',' csv;perintah tetapi tanpa tabel yang dibuat saya dapatkan ERROR: relation "table" does not exist. Jika saya menambahkan tabel kosong, saya tidak mendapatkan kesalahan, tetapi tidak ada yang terjadi. Saya mencoba perintah ini dua atau tiga kali dan tidak ada output atau pesan, tetapi tabel tidak diperbarui ketika saya memeriksanya melalui PGAdmin.

Apakah ada cara untuk mengimpor tabel dengan tajuk yang disertakan seperti yang saya coba lakukan?

Piala Stanley Phil
sumber
2
Meja Anda diberi nama table? Sangat membingungkan. Apakah tabel ada, atau Anda ingin membuatnya berdasarkan CSV? (Anda tidak bisa)
wildplasser
1
baik, saya menamakannya sesuatu yang lain, tetapi untuk contoh ini mari kita sebut tabel. Saya mencoba dengan dan tanpa itu, saya juga mencoba melakukannya \copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;dengan tidak berhasil. Idealnya, tabel dapat dibuat melalui CSV saja, dan menggunakan header di file itu.
Piala Stanley Phil
2
Perhatian bagi siapa saja yang berencana mengubah csv besar menjadi tabel postgres - postgres dibatasi pada 1600 kolom dalam satu tabel. Anda tidak dapat membagi tabel menjadi tabel berukuran 1.600 kolom dan kemudian menggabungkannya setelahnya. Anda perlu mendesain ulang db.
Achekroud
Jika python tersedia untuk Anda, Anda dapat menggunakan d6tstack . Ini juga menangani perubahan skema.
citynorman

Jawaban:

135

Ini berhasil. Baris pertama memiliki nama kolom di dalamnya.

COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER
G. Cito
sumber
5
Saya pikir masalah dengan perintah ini adalah, Anda harus menjadi superuser DB. \ copy berfungsi sebagai pengguna biasa, juga
Exocom
29
COPYtidak membuat tabel atau menambahkan kolom ke dalamnya, ia menambahkan baris ke tabel yang sudah ada dengan kolom yang sudah ada. Agaknya penanya ingin mengotomatiskan pembuatan ~ 100 kolom, dan COPYtidak memiliki fungsi ini, setidaknya pada PG 9.3.
Daniel Vérité
2
@Exocarcap bagus. Karena saya tidak pernah menjadi admin atau superuser untuk DB pada sistem postgres yang saya gunakan (pgadmin menjadikan saya pemilik dari database yang saya gunakan dan memberi saya hak istimewa / peran terbatas) Saya pasti telah menggunakan `\ COPY '. Cheers
G. Cito
2
@Daniel Saya memahami tabel pengguna sudah ada dan memiliki semua kolom yang mereka butuhkan dan bahwa mereka hanya inginADD data.
G. Cito
Punya syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADERpada aws pergeseran merah.
Mithril
24

Dengan pustaka Python pandas, Anda dapat dengan mudah membuat nama kolom dan menyimpulkan tipe data dari file 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)

The if_existsParameter dapat diatur untuk mengganti atau append ke tabel yang ada, misalnya df.to_sql('pandas_db', engine, if_exists='replace'). Ini juga berfungsi untuk jenis file masukan tambahan, dokumen di sini dan di sini .

joelostblom
sumber
1
Saya menemukan bahwa pd.DataFrame.from_csv memberi saya lebih sedikit masalah, tetapi jawaban ini sejauh ini adalah cara termudah untuk melakukan ini, IMO.
Brock
Benar, saya tidak yakin mengapa saya mengetik pd.read_excel, bukan pd.read_csv. Saya memperbarui jawabannya.
joelostblom
1
ini adalah solusi yang bagus untuk saat Anda tidak ingin membuat tabel yang akan menampung csv besar. Sekadar pemberitahuan - postgres hanya dapat mengambil 1.600 kolom dalam sebuah tabel. Rupanya mesin DB lain akan mengizinkan lebih banyak. Memiliki banyak kolom ini tampaknya merupakan bentuk SQL yang buruk, meskipun konsensus ini belum disaring hingga epidemiologi.
Achekroud
1
Secara default df.to_sql()SANGAT LAMBAT, untuk mempercepatnya anda bisa menggunakan d6tstack . Ini juga menangani perubahan skema.
citynorman
13

Alternatif dengan terminal tanpa izin

The pg dokumentasi di CATATAN katakanlah

Path akan diinterpretasikan relatif terhadap direktori kerja dari proses server (biasanya direktori data cluster), bukan direktori kerja klien.

Jadi, secara keseluruhan, menggunakan psqlatau klien apapun, bahkan di server lokal, Anda memiliki masalah ... Dan, jika Anda mengekspresikan perintah COPY untuk pengguna lain, mis. di README Github, pembaca akan mengalami masalah ...

Satu-satunya cara untuk mengekspresikan jalur relatif dengan izin klien menggunakan STDIN ,

Ketika STDIN atau STDOUT ditentukan, data dikirim melalui koneksi antara klien dan server.

seperti yang diingat di sini :

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

Saya telah menggunakan fungsi ini untuk beberapa waktu tanpa masalah. Anda hanya perlu memberikan kolom angka yang ada di file csv, dan itu akan mengambil nama header dari baris pertama dan membuat tabel untuk Anda:

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;
mehmet
sumber
jangan lupa untuk mengubah set schema 'data';apa pun yang terjadi untuk Anda
mehmet
0

Anda dapat menggunakan d6tstack yang membuat tabel untuk Anda dan lebih cepat daripada pd.to_sql () karena menggunakan perintah impor DB asli. Ini mendukung Postgres serta MYSQL dan 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')

Ini juga berguna untuk mengimpor beberapa CSV, menyelesaikan perubahan skema data dan / atau praproses dengan panda (misalnya untuk tanggal) sebelum menulis ke db, lihat lebih jauh di buku catatan contoh

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
citynorman.dll
sumber