Come importare i dati dei file CSV in una tabella PostgreSQL?


602

Come posso scrivere una procedura memorizzata che importa i dati da un file CSV e popola la tabella?


18
Perché una procedura memorizzata? COPY fa il trucco
Frank Heikens il

1
Ho un'interfaccia utente che carica il file CSV, per collegarlo ho bisogno della procedura memorizzata che copia effettivamente i dati dal file
CSV

3
potresti approfondire come usare la COPIA?
Vardhan,

17
Bozhidar Batsov ti ha già fornito un link a un esempio, il manuale potrebbe anche aiutare: postgresql.org/docs/8.4/interactive/sql-copy.html
Frank Heikens,

Risposte:


775

Dai un'occhiata a questo breve articolo .


Soluzione parafrasata qui:

Crea il tuo tavolo:

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

Copia i dati dal tuo file CSV nella tabella:

COPY zip_codes FROM '/path/to/csv/ZIP_CODES.txt' WITH (FORMAT csv);

46
effettivamente usare \ copy farebbe lo stesso trucco se non si dispone dell'accesso superutente; si lamenta del mio Fedora 16 quando uso COPY con un account non root.
chiede il

81
SUGGERIMENTO: puoi indicare quali colonne hai nel CSV usando zip_codes (col1, col2, col3). Le colonne devono essere elencate nello stesso ordine in cui appaiono nel file.
David Pelaez,

6
@ chiedew0rder \ copy ha la stessa sintassi? bcoz Ricevo un errore di sintassi con \ copy
JhovaniC

6
Devo includere la riga di intestazione?
bernie2436,

116
Puoi facilmente includere la riga di intestazione - aggiungi HEADER nelle opzioni: 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

Se non si dispone dell'autorizzazione per l'uso COPY(che funziona sul server db), è possibile utilizzare \copyinvece (che funziona nel client db). Utilizzando lo stesso esempio di Bozhidar Batsov:

Crea il tuo tavolo:

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

Copia i dati dal tuo file CSV nella tabella:

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

Puoi anche specificare le colonne da leggere:

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

Vedi la documentazione per COPIA :

Non confondere COPIA con l'istruzione psql \ copia. \ copy richiama COPY DA STDIN o COPY TO STDOUT, quindi recupera / archivia i dati in un file accessibile al client psql. Pertanto, l'accessibilità dei file e i diritti di accesso dipendono dal client anziché dal server quando viene utilizzato \ copy.

e nota:

Per le colonne di identità, il comando COPIA DA scriverà sempre i valori di colonna forniti nei dati di input, come l'opzione INSERT OVERRIDING SYSTEM VALUE.


\ copy voters (ZIP, CITY) DA '/Users/files/Downloads/WOOD.TXT' DELIMITER ',' CSV HEADER; ERRORE: dati extra dopo l'ultima colonna prevista CONTESTO: COPIA elettori, riga 2: "OH0012781511,87.26953, HOUSEHOLDER, SHERRY, LEIGH ,, 11/26 / 1965,08 / 19/1988,, 211 N GARFIELD ST,, BLOOMD ... "
JZ.

@JZ. Ho avuto un errore simile. Era perché avevo colonne vuote extra. Controlla il tuo CSV e se hai colonne vuote, questo potrebbe essere il motivo.
alex bennett,

5
Questo è in qualche modo fuorviante: la differenza tra COPYed \copyè molto più di un semplice permesso, e non puoi semplicemente aggiungere un `` per farlo funzionare magicamente. Vedere la descrizione (nel contesto di esportazione) qui: stackoverflow.com/a/1517692/157957
IMSoP

@IMSoP: hai ragione, ho aggiunto una menzione di server e client per chiarire
bjelli

@bjelli è \ copy più lento di copy? Ho un file da 1,5 MB e un'istanza db.m4.large su RDS ed è stato ore che questo comando di copia è stato eseguito (almeno 3).
Sebastian,

79

Un modo rapido per farlo è con la libreria panda Python (la versione 0.15 o successiva funziona meglio). Questo gestirà la creazione delle colonne per te, anche se ovviamente le scelte che fa per i tipi di dati potrebbero non essere ciò che desideri. Se non fa esattamente ciò che desideri, puoi sempre utilizzare il codice "crea tabella" generato come modello.

Ecco un semplice esempio:

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)

Ed ecco un po 'di codice che mostra come impostare varie opzioni:

# 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]

6
Inoltre, il if_existsparametro può essere impostato per sostituire o aggiungere a una tabella esistente, ad es.df.to_sql("fhrs", engine, if_exists='replace')
joelostblom

1
nome utente e password: è necessario creare Login e assegnare DB all'utente. Se utilizza pgAdmin, quindi creare "Ruolo di accesso / ruolo di gruppo" utilizzando la GUI
Somnath Kadam

9
Panda è un modo super lento di caricare su sql (vs file CSV). Gli ordini di grandezza possono essere più lenti.
user48956

Questo potrebbe essere un modo per scrivere dati ma è super lento anche con batch e buona potenza di calcolo. L'uso di CSV è un buon modo per ottenere questo risultato.
Ankit Singh,

df.to_sql()è molto lento, è possibile utilizzare d6tstack.utils.pd_to_psql()da d6tstack vedere il confronto delle prestazioni
citynorman

30

È inoltre possibile utilizzare pgAdmin, che offre una GUI per eseguire l'importazione. Questo è mostrato in questo thread SO . Il vantaggio dell'utilizzo di pgAdmin è che funziona anche per database remoti.

Proprio come le soluzioni precedenti, tuttavia, è necessario disporre già della tabella nel database. Ogni persona ha la sua soluzione, ma quello che faccio di solito è aprire il CSV in Excel, copiare le intestazioni, incollare speciali con trasposizione su un foglio di lavoro diverso, posizionare il tipo di dati corrispondente nella colonna successiva, quindi semplicemente copiarlo e incollarlo in un editor di testo insieme alla query di creazione della tabella SQL appropriata in questo modo:

CREATE TABLE my_table (
    /*paste data from Excel here for example ... */
    col_1 bigint,
    col_2 bigint,
    /* ... */
    col_n bigint 
)

1
ti preghiamo di mostrare un paio di righe di esempio dei tuoi dati incollati
apriranno il

29

La maggior parte delle altre soluzioni qui richiede di creare la tabella in anticipo / manualmente. Questo potrebbe non essere pratico in alcuni casi (ad esempio, se nella tabella di destinazione sono presenti molte colonne). Quindi, l'approccio che segue potrebbe tornare utile.

Fornendo il percorso e il conteggio delle colonne del file CSV, è possibile utilizzare la seguente funzione per caricare la tabella in una tabella temporanea che verrà denominata come target_table:

Si presume che la riga superiore abbia i nomi delle colonne.

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;

1
Ciao Mehmet, grazie per la risposta che hai pubblicato ma quando
eseguo il

user2867432 devi cambiare il nome dello schema che usi di conseguenza (es. public)
mehmet

Ciao Mehmet, grazie per la soluzione, è perfetto, ma funziona solo se l'utente DB di Postgres è un superutente, esiste un modo per farlo funzionare senza un superutente?
Geeme,

Geeme: leggi "security definer" qui , ma non l'ho usato da solo.
Mehmet,

Bella risposta! Non sto andando troppo generico nel mio codice per la leggibilità per gli altri.
Manohar Reddy Poreddy il

19

Come menzionato da Paolo, l'importazione funziona in pgAdmin:

tasto destro del mouse sulla tabella -> importa

seleziona file locale, formato e codifica

ecco uno screenshot tedesco della GUI di pgAdmin:

GUI di importazione pgAdmin

cosa simile che puoi fare con DbVisualizer (ho una licenza, non sono sicuro della versione gratuita)

fare clic con il tasto destro su una tabella -> Importa dati tabella ...

DbVisualizer import GUI


2
DBVisualizer ha impiegato 50 secondi per importare 1400 righe con tre campi - e ho dovuto riportare tutto da una stringa a qualunque cosa dovesse essere.
Noumenon,

19
COPY table_name FROM 'path/to/data.csv' DELIMITER ',' CSV HEADER;

10
  1. crea prima una tabella

  2. Quindi utilizzare il comando copia per copiare i dettagli della tabella:

copia table_name (C1, C2, C3 ....)
da 'percorso al tuo file csv' delimitatore ',' intestazione csv;

Grazie


3
In che modo questa non è la risposta accettata? Perché dovrei scrivere uno script Python quando il database ha già un comando per farlo?
Wes,


8

Esperienza personale con PostgreSQL, ancora in attesa di un modo più veloce.

1. Creare prima lo scheletro della tabella se il file è archiviato localmente:

    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. Quando \ path \ xxx.csv è sul server, postgreSQL non ha i permessi per accedere al server, dovrai importare il file .csv attraverso la funzionalità integrata di pgAdmin.

Fare clic con il tasto destro del mouse sul nome della tabella e selezionare Importa.

inserisci qui la descrizione dell'immagine

Se il problema persiste, consulta questo tutorial. http://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/


6

Come importare i dati dei file CSV in una tabella PostgreSQL?

passaggi:

  1. È necessario collegare il database postgresql nel terminale

    psql -U postgres -h localhost
  2. È necessario creare un database

    create database mydb;
  3. È necessario creare l'utente

    create user siva with password 'mypass';
  4. Connettiti con il database

    \c mydb;
  5. È necessario creare uno schema

    create schema trip;
  6. È necessario creare una tabella

    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. Importa i dati del file CSV in 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. Trova i dati della tabella dati

    select * from trip.test;

5

IMHO, il modo più conveniente è seguire " Importa dati CSV in postgresql, il modo più comodo ;-) ", usando csvsql di csvkit , che è un pacchetto Python installabile tramite pip.


3
Link marc è vorace! L'articolo a cui hai collegato non funziona più, il che mi mette a disagio :(
chbrown,

potresti voler dire che il suo è py.
alpinista

1
Per me ottengo un MemoryError se provo a importare un CSV di grandi dimensioni, quindi sembra che non sia in streaming.
DavidC,

@DavidC Interessante. Quanto è grande il tuo file? Quanta memoria hai? Se non viene riprodotto in streaming come appare, suggerisco di raggruppare i dati prima dell'inserimento
sal

1
Il file aveva una dimensione di 5 GB e ho 2 GB di memoria. Mi sono arreso e ho usato uno script per generare i comandi CREATE TABLE e COPY alla fine.
DavidC,

3

In Python, puoi usare questo codice per la creazione automatica di tabelle PostgreSQL con nomi di colonne:

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)

È anche relativamente veloce, posso importare più di 3,3 milioni di righe in circa 4 minuti.


2

Puoi anche usare pgfutter o, ancora meglio, pgcsv .

pgfutter è abbastanza difettoso, lo consiglierei pgcsv.

Ecco come farlo con pgcsv:

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

1

Se hai bisogno di un meccanismo semplice per importare da CSV multilinea text / parse puoi usare:

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;

DBFiddle Demo


1

DBeaver Community Edition (dbeaver.io) semplifica la connessione a un database, quindi importa un file CSV per il caricamento su un database PostgreSQL. Inoltre, semplifica l'emissione di query, il recupero di dati e il download di set di risultati in formato CSV, JSON, SQL o altri formati di dati comuni.

È uno strumento di database multipiattaforma FOSS per programmatori, DBA e analisti SQL che supporta tutti i database più diffusi: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, ecc. È un concorrente FOSS valido per TOAD per Postgres, TOAD per SQL Server o Toad per Oracle.

Non ho alcuna affiliazione con DBeaver. Adoro il prezzo (GRATUITO!) E la piena funzionalità, ma vorrei che aprissero di più questa applicazione DBeaver / Eclipse e rendessero più semplice l'aggiunta di widget di analisi a DBeaver / Eclipse, piuttosto che richiedere agli utenti di pagare l'abbonamento annuale di $ 199 solo per creare grafici e diagrammi direttamente all'interno dell'applicazione. Le mie capacità di programmazione Java sono arrugginite e non ho voglia di settimane per imparare di nuovo a costruire widget di Eclipse, (solo per scoprire che DBeaver ha probabilmente disabilitato la possibilità di aggiungere widget di terze parti a DBeaver Community Edition.)

Gli utenti esperti di DBeaver che sono sviluppatori Java possono fornire informazioni dettagliate sui passaggi per creare widget di analisi da aggiungere alla Community Edition di DBeaver?


Sarebbe stato bello capire come usare DBeaver per importare un file CSV. Comunque, questo potrebbe aiutare: dbeaver.com/docs/wiki/Data-transfer
umbe1987

0

Creare una tabella e disporre delle colonne necessarie per la creazione della tabella nel file CSV.

  1. Apri Postgres e fai clic con il pulsante destro del mouse sulla tabella di destinazione che desideri caricare e seleziona Importa e aggiorna i seguenti passaggi nella sezione Opzioni file

  2. Ora sfoglia il tuo file nel nome del file

  3. Seleziona CSV nel formato

  4. Codifica come ISO_8859_5

Ora vai a Misc. opzioni e controllare l'intestazione e fare clic su import.


0

Ho creato un piccolo strumento che importa csvfile in PostgreSQL super facile, solo un comando e creerà e popolerà le tabelle, sfortunatamente, al momento tutti i campi creati automaticamente usano il tipo TEXT

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

Lo strumento è disponibile su https://github.com/eduardonunesp/csv2pg


Hai creato uno strumento separato per l'equivalente di psql -h 192.168.99.100 -U postgres mydatabase -c "COPY users FROM 'users.csv' DELIMITER ';' CSV"? Immagino che la parte in cui viene creata la tabella sia piacevole, ma poiché ogni campo è di testo non è super utile
GammaGames

1
Ops, grazie per il testa a testa. Sì, l'ho fatto, beh, ci sono volute solo poche ore e ho imparato cose interessanti in Go e pq e API del database in Go.
Eduardo Pereira,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.