Come copiare dal file CSV alla tabella PostgreSQL con le intestazioni nel file CSV?


93

Voglio copiare un file CSV in una tabella Postgres. Ci sono circa 100 colonne in questa tabella, quindi non voglio riscriverle se non devo.

Sto usando il \copy table from 'table.csv' delimiter ',' csv;comando ma senza una tabella creata ottengo ERROR: relation "table" does not exist. Se aggiungo una tabella vuota non ottengo alcun errore, ma non succede nulla. Ho provato questo comando due o tre volte e non c'erano output o messaggi, ma la tabella non è stata aggiornata quando l'ho controllata tramite PGAdmin.

C'è un modo per importare una tabella con intestazioni incluse come sto cercando di fare?


2
Il tuo tavolo si chiama table? Molto confuso. La tabella esiste o vuoi crearla in base al CSV? (non puoi)
wildplasser

1
beh, l'ho chiamato qualcos'altro, ma per questo esempio chiamiamolo table. Ho provato con e senza che \copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;esistesse ho anche provato a farlo senza fortuna. Idealmente la tabella potrebbe essere creata tramite il CSV da solo e utilizzare le intestazioni in quel file.
Stanley Cup Phil


2
Solo un avvertimento per chiunque abbia intenzione di trasformare un grande CSV in una tabella postgres: postgres ha un limite di 1600 colonne in una singola tabella. Non è possibile suddividere le tabelle in tabelle delle dimensioni di 1600 colonne e quindi unirle dopo. Devi ridisegnare il db.
Achekroud

Se python è disponibile per te, puoi usare d6tstack . Si occupa anche delle modifiche allo schema.
citynorman

Risposte:


135

Questo ha funzionato. La prima riga conteneva i nomi delle colonne.

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

5
Penso che il problema con questo comando sia che devi essere il superutente del DB. \ copy funziona anche come utente normale
Exocom

29
COPYnon crea una tabella o aggiunge colonne ad essa, aggiunge righe a una tabella esistente con le sue colonne esistenti. Presumibilmente il richiedente vuole automatizzare la creazione di ~ 100 colonne e COPYnon ha questa funzionalità, almeno a partire da PG 9.3.
Daniel Vérité

2
@Exocom buona cattura. Dato che non sono mai un amministratore o un superutente per i DB sui sistemi postgres che utilizzo (il pgadmin mi rende proprietario dei database che utilizzo e mi dà privilegi / ruoli limitati) devo aver usato "\ COPY". Saluti
G. Cito

2
@Daniel ho capito che la tabella dell'utente esisteva già e aveva tutte le colonne di cui avevano bisogno e che volevano semplicemente ADDdati.
G. Cito

Sono syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADERentrato in aws redshift.
Mithril

24

Con la libreria Python pandas, puoi creare facilmente nomi di colonne e dedurre tipi di dati da un 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)

Il if_existsparametro può essere impostato per sostituire o aggiungere a una tabella esistente, ad es df.to_sql('pandas_db', engine, if_exists='replace'). Funziona anche per tipi di file di input aggiuntivi, documenti qui e qui .


1
Trovo che pd.DataFrame.from_csv mi dia meno problemi, ma questa risposta è di gran lunga il modo più semplice per farlo, IMO.
Brock

È vero, non sono sicuro del motivo per cui ho digitato pd.read_excel, invece di pd.read_csv. Ho aggiornato la risposta.
joelostblom

1
questa è una soluzione fantastica per quando non vuoi pre-creare la tabella che conterrà un grande CSV. Tuttavia, solo un avvertimento: postgres può accettare solo 1600 colonne in una tabella. Apparentemente altri motori DB ne consentiranno di più. Avere così tante colonne è apparentemente una forma SQL scadente, sebbene questo consenso debba ancora filtrare fino all'epidemiologia.
Achekroud

1
Di default df.to_sql()è MOLTO LENTO, per accelerare puoi usare d6tstack . Si occupa anche delle modifiche allo schema.
citynorman

13

Alternativa tramite terminale senza autorizzazione

La documentazione pg in NOTES dice

Il percorso verrà interpretato in relazione alla directory di lavoro del processo del server (normalmente la directory dei dati del cluster), non alla directory di lavoro del client.

Quindi, geralmente, usando psqlo qualsiasi client, anche in un server locale, hai problemi ... E, se stai esprimendo il comando COPY per altri utenti, ad es. in un README di Github, il lettore avrà problemi ...

L'unico modo per esprimere il percorso relativo con le autorizzazioni del client è usare STDIN ,

Quando si specifica STDIN o STDOUT, i dati vengono trasmessi tramite la connessione tra il client e il server.

come ricordato qui :

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

3

Utilizzo questa funzione da tempo senza problemi. Devi solo fornire le colonne numeriche presenti nel file csv e prenderà i nomi delle intestazioni dalla prima riga e creerà la tabella per te:

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;

non dimenticare di passare set schema 'data';a qualunque cosa sia per te
mehmet

0

Puoi utilizzare d6tstack che crea la tabella per te ed è più veloce di pd.to_sql () perché utilizza comandi di importazione DB nativi. Supporta Postgres così come MYSQL e 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')

È anche utile per importare più CSV, risolvere le modifiche allo schema dei dati e / o preelaborare con i panda (ad esempio per le date) prima di scrivere su db, vedere più in basso negli esempi del taccuino

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
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.