Bagaimana cara mengimpor data file CSV ke tabel PostgreSQL?

602

Bagaimana saya bisa menulis prosedur tersimpan yang mengimpor data dari file CSV dan mengisi tabel?

Vardhan
sumber
18
Mengapa prosedur tersimpan? COPY melakukan trik
Frank Heikens
1
Saya memiliki antarmuka pengguna yang mengunggah file csv, untuk menghubungkan ini saya memerlukan prosedur tersimpan yang benar-benar menyalin data dari file cvs
vardhan
3
Bisakah Anda menguraikan cara menggunakan COPY?
vardhan
17
Bozhidar Batsov telah memberi Anda tautan ke sebuah contoh, manual yang bagus juga dapat membantu: postgresql.org/docs/8.4/interactive/sql-copy.html
Frank Heikens
5
Manual saat ini: postgresql.org/docs/current/static/sql-copy.html
Basil Bourque

Jawaban:

775

Lihatlah artikel singkat ini .


Solusi diparafrasekan di sini:

Buat meja Anda:

CREATE TABLE zip_codes 
(ZIP char(5), LATITUDE double precision, LONGITUDE double precision, 
CITY varchar, STATE char(2), COUNTY varchar, ZIP_CLASS varchar);

Salin data dari file CSV Anda ke tabel:

COPY zip_codes FROM '/path/to/csv/ZIP_CODES.txt' WITH (FORMAT csv);
Bozhidar Batsov
sumber
46
sebenarnya menggunakan \ copy akan melakukan trik yang sama jika Anda tidak memiliki akses pengguna super; itu keluhan pada Fedora 16 saya saat menggunakan COPY dengan akun non-root.
asksw0rder
81
TIP: Anda dapat menunjukkan kolom apa yang Anda miliki di CSV menggunakan zip_codes (col1, col2, col3). Kolom harus terdaftar dalam urutan yang sama dengan yang muncul di file.
David Pelaez
6
@ asksw0rder apakah \ salin memiliki sintaks yang sama? bcoz Saya mendapatkan kesalahan sintaks dengan \ copy
JhovaniC
6
Haruskah saya sertakan baris tajuk?
bernie2436
116
Anda dapat dengan mudah memasukkan baris tajuk - cukup tambahkan HEADER di dalam opsi: COPY zip_codes FROM '/path/to/csv/ZIP_CODES.txt' DELIMITER ',' CSV HEADER; postgresql.org/docs/9.1/static/sql-copy.html
Barrett Clark
222

Jika Anda tidak memiliki izin untuk menggunakan COPY(yang berfungsi pada server db), Anda dapat menggunakan \copysebagai gantinya (yang bekerja di klien db). Menggunakan contoh yang sama dengan Bozhidar Batsov:

Buat meja Anda:

CREATE TABLE zip_codes 
(ZIP char(5), LATITUDE double precision, LONGITUDE double precision, 
CITY varchar, STATE char(2), COUNTY varchar, ZIP_CLASS varchar);

Salin data dari file CSV Anda ke tabel:

\copy zip_codes FROM '/path/to/csv/ZIP_CODES.txt' DELIMITER ',' CSV

Anda juga dapat menentukan kolom untuk dibaca:

\copy zip_codes(ZIP,CITY,STATE) FROM '/path/to/csv/ZIP_CODES.txt' DELIMITER ',' CSV

Lihat dokumentasi untuk COPY :

Jangan bingung COPY dengan instruksi psql \ copy. \ copy meminta COPY DARI STDIN atau COPY TO STDOUT, dan kemudian mengambil / menyimpan data dalam file yang dapat diakses oleh klien psql. Dengan demikian, aksesibilitas file dan hak akses bergantung pada klien daripada server ketika \ copy digunakan.

dan perhatikan:

Untuk kolom identitas, perintah COPY FROM akan selalu menulis nilai kolom yang disediakan dalam data input, seperti opsi INSERT OVERRIDING SYSTEM VALUE.

bjelli
sumber
\ copy pemilih (ZIP, CITY) DARI '/ Pengguna / file / Unduhan /WOOD.TXT' DELIMITER ',' CSV HEADER; GALAT: data tambahan setelah kolom yang diharapkan terakhir KONTEKS: COPY pemilih, baris 2: "OH0012781511,87,26953, HOUSEHOLDER, SHERRY, LEIGH ,, 11/26 / 1965,08 / 19/1988,, 211 N GARFIELD ST,, BLOOMD ... "
JZ.
@ JZ. Saya memiliki kesalahan serupa. Itu karena saya punya kolom kosong ekstra. Periksa csv Anda dan jika Anda memiliki kolom kosong, itu bisa menjadi alasannya.
alex bennett
5
Ini agak menyesatkan: perbedaan antara COPYdan \copylebih dari sekadar izin, dan Anda tidak bisa begitu saja menambahkan `` untuk membuatnya berfungsi secara ajaib. Lihat deskripsi (dalam konteks ekspor) di sini: stackoverflow.com/a/1517692/157957
IMSoP
@IMSoP: Anda benar, saya menambahkan sebutkan server dan klien untuk mengklarifikasi
bjelli
@ bjelli \ salin lebih lambat dari salin? Saya memiliki file 1,5MB dan contoh db.m4.large di RDS dan sudah berjam-jam bahwa perintah salin ini telah berjalan (setidaknya 3).
Sebastian
79

Salah satu cara cepat untuk melakukan ini adalah dengan panda Python library (versi 0.15 atau di atas yang terbaik). Ini akan menangani pembuatan kolom untuk Anda - meskipun jelas pilihan yang dibuat untuk tipe data mungkin bukan yang Anda inginkan. Jika tidak cukup melakukan apa yang Anda inginkan, Anda selalu dapat menggunakan kode 'buat tabel' yang dihasilkan sebagai templat.

Berikut ini contoh sederhana:

import pandas as pd
df = pd.read_csv('mypath.csv')
df.columns = [c.lower() for c in df.columns] #postgres doesn't like capitals or spaces

from sqlalchemy import create_engine
engine = create_engine('postgresql://username:password@localhost:5432/dbname')

df.to_sql("my_table_name", engine)

Dan inilah beberapa kode yang menunjukkan kepada Anda cara mengatur berbagai opsi:

# Set it so the raw sql output is logged
import logging
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)

df.to_sql("my_table_name2", 
          engine, 
          if_exists="append",  #options are ‘fail’, ‘replace’, ‘append’, default ‘fail’
          index=False, #Do not output the index of the dataframe
          dtype={'col1': sqlalchemy.types.NUMERIC,
                 'col2': sqlalchemy.types.String}) #Datatypes should be [sqlalchemy types][1]
RobinL
sumber
6
Selain itu, if_existsparameter dapat diatur untuk mengganti atau menambahkan ke tabel yang ada, misalnyadf.to_sql("fhrs", engine, if_exists='replace')
joelostblom
1
nama pengguna dan kata sandi: harus membuat Login dan menetapkan DB ke pengguna. Jika menggunakan pgAdmin, maka buat "Peran Login / Grup" menggunakan GUI
Somnath Kadam
9
Panda adalah cara super lambat memuat ke sql (vs file csv). Bisa jadi pesanan lebih lambat lebih lambat.
user48956
Ini bisa menjadi cara untuk menulis data tetapi sangat lambat bahkan dengan batch dan daya komputasi yang baik. Menggunakan CSV adalah cara yang baik untuk mencapai ini.
Ankit Singh
df.to_sql()sangat lambat, Anda dapat menggunakan d6tstack.utils.pd_to_psql()dari d6tstack melihat perbandingan kinerja
citynorman
30

Anda juga dapat menggunakan pgAdmin, yang menawarkan GUI untuk melakukan impor. Itu ditampilkan di utas SO ini . Keuntungan menggunakan pgAdmin adalah ia juga berfungsi untuk basis data jauh.

Sama seperti solusi sebelumnya, Anda harus sudah memiliki tabel di database. Setiap orang memiliki solusi sendiri tetapi yang biasanya saya lakukan adalah membuka CSV di Excel, menyalin tajuk, menempelkan khusus dengan transposisi pada lembar kerja yang berbeda, tempatkan tipe data yang sesuai di kolom berikutnya kemudian salin dan tempel ke editor teks bersama dengan kueri pembuatan tabel SQL yang sesuai seperti:

CREATE TABLE my_table (
    /*paste data from Excel here for example ... */
    col_1 bigint,
    col_2 bigint,
    /* ... */
    col_n bigint 
)
Paul
sumber
1
tolong perlihatkan beberapa baris sampel dari data yang Anda tempel
dcorking
29

Sebagian besar solusi lain di sini mengharuskan Anda membuat tabel terlebih dahulu / secara manual. Ini mungkin tidak praktis dalam beberapa kasus (misalnya, jika Anda memiliki banyak kolom di tabel tujuan). Jadi, pendekatan di bawah ini mungkin berguna.

Menyediakan jumlah lintasan dan kolom file csv Anda, Anda dapat menggunakan fungsi berikut untuk memuat tabel Anda ke tabel temp yang akan dinamai sebagai target_table:

Baris atas diasumsikan memiliki nama kolom.

create or replace function data.load_csv_file
(
    target_table text,
    csv_path text,
    col_count integer
)

returns void as $$

declare

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

begin
    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_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
    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
1
Halo Mehmet, terima kasih atas jawaban yang Anda kirim tetapi ketika saya menjalankan kode Anda, saya mendapatkan pesan kesalahan berikut: ERROR: skema "data" tidak ada
user2867432
user2867432 Anda perlu mengubah nama skema yang Anda gunakan sesuai (misalnya, public)
mehmet
Halo Mehmet, Terima kasih atas solusinya, sempurna tetapi ini hanya berfungsi jika pengguna postgres DB adalah pengguna super, adakah cara untuk membuatnya berfungsi tanpa pengguna super?
Geeme
Geeme: baca "definisi keamanan" di sini , tapi saya belum menggunakannya sendiri.
mehmet
Jawaban yang indah! Saya tidak akan terlalu generik dalam kode saya untuk dibaca oleh orang lain.
Manohar Reddy Poreddy
19

Seperti yang disebutkan Paul, impor berfungsi di pgAdmin:

klik kanan pada tabel -> impor

pilih file, format, dan pengkodean lokal

di sini adalah tangkapan layar pgAdmin Jerman:

pgAdmin mengimpor GUI

hal serupa dapat Anda lakukan dengan DbVisualizer (Saya punya lisensi, tidak yakin tentang versi gratis)

klik kanan pada tabel -> Impor Data Tabel ...

DbVisualizer mengimpor GUI

Andreas L.
sumber
2
DBVisualizer memerlukan waktu 50 detik untuk mengimpor 1400 baris dengan tiga bidang - dan saya harus mengembalikan semuanya dari sebuah String ke apa pun yang seharusnya.
Noumenon
19
COPY table_name FROM 'path/to/data.csv' DELIMITER ',' CSV HEADER;
timxor
sumber
10
  1. buat tabel terlebih dahulu

  2. Kemudian gunakan perintah salin untuk menyalin detail tabel:

salin table_name (C1, C2, C3 ....)
dari 'path ke file csv Anda' pembatas ',' header csv;

Terima kasih

pengguna9130085
sumber
3
Bagaimana ini bukan jawaban yang diterima? Mengapa saya menulis skrip python ketika database sudah memiliki perintah untuk melakukan ini?
Wes
8

Pengalaman pribadi dengan PostgreSQL, masih menunggu cara yang lebih cepat.

1. Buat kerangka tabel terlebih dahulu jika file disimpan secara lokal:

    drop table if exists ur_table;
    CREATE TABLE ur_table
    (
        id serial NOT NULL,
        log_id numeric, 
        proc_code numeric,
        date timestamp,
        qty int,
        name varchar,
        price money
    );
    COPY 
        ur_table(id, log_id, proc_code, date, qty, name, price)
    FROM '\path\xxx.csv' DELIMITER ',' CSV HEADER;

2. Ketika \ path \ xxx.csv ada di server, postgreSQL tidak memiliki izin untuk mengakses server, Anda harus mengimpor file .csv melalui fungsionalitas bawaan pgAdmin.

Klik kanan nama tabel pilih impor.

masukkan deskripsi gambar di sini

Jika Anda masih memiliki masalah, silakan merujuk tutorial ini. http://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/

bunga
sumber
6

Bagaimana cara mengimpor data file CSV ke tabel PostgreSQL?

Langkah:

  1. Perlu menghubungkan database postgresql di terminal

    psql -U postgres -h localhost
  2. Perlu membuat basis data

    create database mydb;
  3. Perlu membuat pengguna

    create user siva with password 'mypass';
  4. Terhubung dengan basis data

    \c mydb;
  5. Perlu membuat skema

    create schema trip;
  6. Perlu membuat tabel

    create table trip.test(VendorID int,passenger_count int,trip_distance decimal,RatecodeID int,store_and_fwd_flag varchar,PULocationID int,DOLocationID int,payment_type decimal,fare_amount decimal,extra decimal,mta_tax decimal,tip_amount decimal,tolls_amount int,improvement_surcharge decimal,total_amount
    );
  7. Impor data file csv ke postgresql

    COPY trip.test(VendorID int,passenger_count int,trip_distance decimal,RatecodeID int,store_and_fwd_flag varchar,PULocationID int,DOLocationID int,payment_type decimal,fare_amount decimal,extra decimal,mta_tax decimal,tip_amount decimal,tolls_amount int,improvement_surcharge decimal,total_amount) FROM '/home/Documents/trip.csv' DELIMITER ',' CSV HEADER;
  8. Temukan data tabel yang diberikan

    select * from trip.test;
sivamani
sumber
5

IMHO, cara paling mudah adalah mengikuti " Impor data CSV ke postgresql, cara yang nyaman ;-) ", menggunakan csvsql dari csvkit , yang merupakan paket python yang dapat diinstal melalui pip.

sal
sumber
3
Pembusukan tautan sangat rakus! Artikel yang Anda
tautkan
Anda mungkin ingin menyebutkan bahwa itu adalah py.
mountainclimber
1
Bagi saya, saya mendapatkan MemoryError jika mencoba mengimpor CSV besar sehingga sepertinya tidak mengalir.
DavidC
@DavidC Menarik. Seberapa besar file Anda? Berapa banyak memori yang Anda miliki? Jika itu tidak mengalir seperti yang muncul, saya sarankan chunking data sebelum penyisipan
sal
1
Ukuran file 5GB dan saya punya memori 2GB. Saya menyerah dan menggunakan skrip untuk menghasilkan perintah CREATE TABLE dan COPY pada akhirnya.
DavidC
3

Dengan Python, Anda dapat menggunakan kode ini untuk pembuatan tabel PostgreSQL otomatis dengan nama kolom:

import pandas, csv

from io import StringIO
from sqlalchemy import create_engine

def psql_insert_copy(table, conn, keys, data_iter):
    dbapi_conn = conn.connection
    with dbapi_conn.cursor() as cur:
        s_buf = StringIO()
        writer = csv.writer(s_buf)
        writer.writerows(data_iter)
        s_buf.seek(0)
        columns = ', '.join('"{}"'.format(k) for k in keys)
        if table.schema:
            table_name = '{}.{}'.format(table.schema, table.name)
        else:
            table_name = table.name
        sql = 'COPY {} ({}) FROM STDIN WITH CSV'.format(table_name, columns)
        cur.copy_expert(sql=sql, file=s_buf)

engine = create_engine('postgresql://user:password@localhost:5432/my_db')

df = pandas.read_csv("my.csv")
df.to_sql('my_table', engine, schema='my_schema', method=psql_insert_copy)

Ini juga relatif cepat, saya dapat mengimpor lebih dari 3,3 juta baris dalam waktu sekitar 4 menit.

Marc
sumber
2

Anda juga dapat menggunakan pgfutter , atau, lebih baik lagi, pgcsv .

pgfutter cukup buggy, saya akan merekomendasikan pgcsv.

Berikut cara melakukannya dengan pgcsv:

sudo pip install pgcsv
pgcsv --db 'postgresql://localhost/postgres?user=postgres&password=...' my_table my_file.csv
Vlad Dinulescu
sumber
1

Jika Anda memerlukan mekanisme sederhana untuk mengimpor dari teks / parsing CSV multiline, Anda dapat menggunakan:

CREATE TABLE t   -- OR INSERT INTO tab(col_names)
AS
SELECT
   t.f[1] AS col1
  ,t.f[2]::int AS col2
  ,t.f[3]::date AS col3
  ,t.f[4] AS col4
FROM (
  SELECT regexp_split_to_array(l, ',') AS f
  FROM regexp_split_to_table(
$$a,1,2016-01-01,bbb
c,2,2018-01-01,ddd
e,3,2019-01-01,eee$$, '\n') AS l) t;

Demo DBFiddle

Lukasz Szozda
sumber
1

DBeaver Community Edition (dbeaver.io) membuatnya mudah untuk terhubung ke database, lalu mengimpor file CSV untuk diunggah ke database PostgreSQL. Ini juga memudahkan untuk mengeluarkan kueri, mengambil data, dan mengunduh set hasil ke CSV, JSON, SQL, atau format data umum lainnya.

Ini adalah alat database multi-platform FOSS untuk pemrogram SQL, DBA, dan analis yang mendukung semua basis data populer: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, dll. Ini adalah pesaing FOSS yang layak untuk TOAD untuk Postgres, TOAD untuk SQL Server, atau Toad untuk Oracle.

Saya tidak memiliki afiliasi dengan DBeaver. Saya suka harga (GRATIS!) Dan fungsionalitas penuh, tetapi saya berharap mereka akan membuka aplikasi DBeaver / Eclipse ini lebih banyak dan membuatnya mudah untuk menambahkan widget analitik ke DBeaver / Eclipse, daripada meminta pengguna untuk membayar langganan tahunan $ 199 hanya untuk membuat grafik dan grafik langsung di dalam aplikasi. Keterampilan pengkodean Java saya berkarat dan saya tidak ingin menghabiskan waktu berminggu-minggu untuk mempelajari kembali cara membuat widget Eclipse, (hanya untuk mengetahui bahwa DBeaver mungkin telah menonaktifkan kemampuan untuk menambahkan widget pihak ketiga ke dalam DBeaver Community Edition.)

Bisakah DBeaver memberi pengguna daya yang merupakan pengembang Java memberikan beberapa wawasan tentang langkah-langkah untuk membuat widget analitik untuk ditambahkan ke dalam Edisi Komunitas DBeaver?

Rich Lysakowski PhD
sumber
Akan lebih baik untuk memahami cara menggunakan DBeaver untuk mengimpor file CSV. Bagaimanapun, ini mungkin membantu: dbeaver.com/docs/wiki/Data-transfer
umbe1987
0

Buat tabel dan memiliki kolom yang diperlukan yang digunakan untuk membuat tabel dalam file csv.

  1. Buka postgres dan klik kanan pada tabel target yang ingin Anda muat & pilih impor dan Perbarui langkah-langkah berikut di bagian opsi file

  2. Sekarang telusuri file Anda dalam nama file

  3. Pilih csv dalam format

  4. Pengkodean sebagai ISO_8859_5

Sekarang kebagian misc. opsi dan periksa tajuk dan klik impor.

suriruler
sumber
0

Saya membuat alat kecil yang mengimpor csvfile ke PostgreSQL super mudah, hanya sebuah perintah dan itu akan membuat dan mengisi tabel, sayangnya, saat ini semua bidang yang dibuat secara otomatis menggunakan jenis TEXT

csv2pg users.csv -d ";" -H 192.168.99.100 -U postgres -B mydatabase

Alat ini dapat ditemukan di https://github.com/eduardonunesp/csv2pg

Eduardo Pereira
sumber
Anda membuat alat terpisah yang setara dengan psql -h 192.168.99.100 -U postgres mydatabase -c "COPY users FROM 'users.csv' DELIMITER ';' CSV"? Saya kira bagian di mana ia menciptakan tabel itu bagus, tetapi karena setiap bidang adalah teks, itu tidak berguna
GammaGames
1
Ops, terima kasih untuk kepala. Ya, saya melakukannya, hanya butuh beberapa jam dan saya belajar hal-hal keren di Go dan pq serta API basis data di Go.
Eduardo Pereira