Comment copier du fichier CSV vers la table PostgreSQL avec des en-têtes dans le fichier CSV?

je veux copier un fichier CSV dans une table Postgres. Il y a environ 100 colonnes de ce tableau, donc je ne veux pas réécrire si je n'ai pas.

j'utilise la commande copy table from 'table.csv' delimiter ',' csv; mais sans table créée je reçois ERROR: relation "table" does not exist . Si j'ajoute un tableau vide je n'obtiens pas d'erreur, mais rien ne se passe. J'ai essayé cette commande deux ou trois fois et il n'y avait pas de sortie ou de messages, mais la table n'était pas mise à jour quand je l'ai vérifiée par PGAdmin.

y a-t-il un moyen d'importer une table avec des en-têtes inclus comme j'essaie de le faire?

54
demandé sur w͏̢in̡͢g͘̕ed̨p̢͟a͞n͏͏t̡͜͝he̸r̴ 2013-07-15 23:50:13

4 réponses

ça a marché. La première rangée contenait des noms de colonne.

COPY wheat FROM 'wheat_crop_data.csv' DELIMITER ';' CSV HEADER
77
répondu G. Cito 2015-08-31 12:46:29

avec la bibliothèque Python pandas , vous pouvez facilement créer des noms de colonne et déduire des types de données à partir d'un fichier 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)

le paramètre if_exists peut être défini pour remplacer ou ajouter à une table existante, par exemple df.to_sql('pandas_db', engine, if_exists='replace') . Cela fonctionne pour les types de fichiers d'entrée supplémentaires aussi bien, docs ici et ici .

23
répondu joelostblom 2015-10-09 01:30:52

Alternative par terminal sans permission

Le pg documentation NOTES dites

le chemin sera interprété par rapport au répertoire de travail du processus serveur (normalement le répertoire de données du cluster), et non par rapport au répertoire de travail du client.

donc, gerally, en utilisant psql ou n'importe quel client, même dans un serveur local, vous avez des problèmes ... Et, si vous exprimez la commande de copie pour d'autres utilisateurs, par exemple: à un GitHub README, le lecteur aura des problèmes ...

la seule façon d'exprimer chemin relatif avec les permissions du client est d'utiliser STDIN ,

lorsque STDIN ou STDOUT est spécifié, les données sont transmises via la connexion entre le client et le serveur.

comme d'ici :

psql -h remotehost -d remote_mydb -U myuser -c \
   "copy mytable (column1, column2) from STDIN with delimiter as ','" \
   < ./relative_path/file.csv
6
répondu Peter Krauss 2017-05-23 12:26:15

j'utilise cette fonction depuis un certain temps sans problème. Vous avez juste besoin de fournir les colonnes de nombre il y a dans le fichier csv, et il prendra les noms d'en-tête de la première ligne et de créer la table pour vous:

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;
3
répondu mehmet 2017-05-25 23:11:36