Comment importer des données de fichier CSV dans une table PostgreSQL?


602

Comment puis-je écrire une procédure stockée qui importe des données à partir d'un fichier CSV et remplit la table?


18
Pourquoi une procédure stockée? COPY fait l'affaire
Frank Heikens

1
J'ai une interface utilisateur qui télécharge le fichier csv, pour le brancher, j'ai besoin de la procédure stockée qui copie réellement les données du fichier cvs
vardhan

3
pourriez-vous nous expliquer comment utiliser la COPIE?
vardhan

17
Bozhidar Batsov vous a déjà donné un lien vers un exemple, le manuel fin pourrait également vous aider: postgresql.org/docs/8.4/interactive/sql-copy.html
Frank Heikens

Réponses:


775

Jetez un œil à ce court article .


Solution paraphrasée ici:

Créez votre table:

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

Copiez les données de votre fichier CSV dans le tableau:

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

46
en fait, utiliser \ copy ferait la même astuce si vous ne disposez pas de l'accès superutilisateur; il se plaint sur mon Fedora 16 lors de l'utilisation de COPY avec un compte non root.
askw0rder

81
CONSEIL: vous pouvez indiquer quelles colonnes vous avez dans le CSV en utilisant zip_codes (col1, col2, col3). Les colonnes doivent être répertoriées dans le même ordre qu'elles apparaissent dans le fichier.
David Pelaez

6
@ askw0rder \ copy a-t-il la même syntaxe? bcoz
J'obtiens

6
Dois-je inclure la ligne d'en-tête?
bernie2436

116
Vous pouvez facilement inclure la ligne d'en-tête - ajoutez simplement HEADER dans les options: 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

Si vous n'êtes pas autorisé à utiliser COPY(qui fonctionne sur le serveur db), vous pouvez utiliser à la \copyplace (qui fonctionne dans le client db). En utilisant le même exemple que Bozhidar Batsov:

Créez votre table:

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

Copiez les données de votre fichier CSV dans le tableau:

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

Vous pouvez également spécifier les colonnes à lire:

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

Voir la documentation de COPY :

Ne confondez pas COPY avec l'instruction \ copy psql. \ copy appelle COPY FROM STDIN ou COPY TO STDOUT, puis récupère / stocke les données dans un fichier accessible au client psql. Ainsi, l'accessibilité des fichiers et les droits d'accès dépendent du client plutôt que du serveur lorsque \ copy est utilisé.

et notez:

Pour les colonnes d'identité, la commande COPY FROM écrit toujours les valeurs de colonne fournies dans les données d'entrée, comme l'option INSERT OVERRIDING SYSTEM VALUE.


\ copier les électeurs (ZIP, VILLE) DE '/Users/files/Downloads/WOOD.TXT' DELIMITER ',' CSV HEADER; ERREUR: données supplémentaires après la dernière colonne attendue CONTEXTE: COPY votants, ligne 2: "OH0012781511,87,26953, MENAGE, SHERRY, LEIGH ,, 11/26 / 1965,08 / 19/1988,, 211 N GARFIELD ST,, BLOOMD ... "
JZ.

@JZ. J'ai eu une erreur similaire. C'était parce que j'avais des colonnes vierges supplémentaires. Vérifiez votre csv et si vous avez des colonnes vides, cela pourrait être la raison.
alex bennett

5
C'est quelque peu trompeur: la différence entre COPYet \copyest bien plus que de simples autorisations, et vous ne pouvez pas simplement ajouter un `` pour que cela fonctionne comme par magie. Voir la description (dans le contexte de l'exportation) ici: stackoverflow.com/a/1517692/157957
IMSoP

@IMSoP: vous avez raison, j'ai ajouté une mention de serveur et client pour clarifier
bjelli

@bjelli est \ copier plus lent que copier? J'ai un fichier de 1,5 Mo et une instance db.m4.large sur RDS et cela fait des heures que cette commande de copie a été exécutée (au moins 3).
Sebastian

79

Un moyen rapide de le faire est d'utiliser la bibliothèque pandas Python (la version 0.15 ou supérieure fonctionne mieux). Cela gérera la création des colonnes pour vous - bien qu'évidemment, les choix qu'il fait pour les types de données ne soient pas ce que vous voulez. S'il ne fait pas tout à fait ce que vous voulez, vous pouvez toujours utiliser le code 'create table' généré comme modèle.

Voici un exemple simple:

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)

Et voici un code qui vous montre comment définir diverses options:

# 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
En outre, le if_existsparamètre peut être défini pour remplacer ou ajouter à une table existante, par exempledf.to_sql("fhrs", engine, if_exists='replace')
joelostblom

1
nom d'utilisateur et mot de passe: besoin de créer un identifiant et d'attribuer une base de données à l'utilisateur. Si utilise pgAdmin, créez un "rôle de connexion / groupe" à l'aide de l'interface graphique
Somnath Kadam

9
Pandas est un moyen super lent de chargement dans sql (vs fichiers csv). Peut être des ordres de grandeur plus lents.
user48956

Cela pourrait être un moyen d'écrire des données, mais c'est très lent même avec un lot et une bonne puissance de calcul. L'utilisation de CSV est un bon moyen d'y parvenir.
Ankit Singh

df.to_sql()est vraiment lent, vous pouvez utiliser à d6tstack.utils.pd_to_psql()partir de d6tstack voir la comparaison des performances
citynorman

30

Vous pouvez également utiliser pgAdmin, qui propose une interface graphique pour effectuer l'importation. Cela est montré dans ce fil SO . L'avantage d'utiliser pgAdmin est qu'il fonctionne également pour les bases de données distantes.

Tout comme les solutions précédentes, vous devez déjà avoir votre table dans la base de données. Chaque personne a sa propre solution, mais ce que je fais habituellement, c'est ouvrir le CSV dans Excel, copier les en-têtes, coller spécial avec transposition sur une autre feuille de calcul, placer le type de données correspondant dans la colonne suivante, puis simplement copier et coller cela dans un éditeur de texte avec la requête de création de table SQL appropriée comme suit:

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

1
les pls montrent quelques exemples de lignes de vos données collées
dcorking

29

La plupart des autres solutions nécessitent ici que vous créiez la table à l'avance / manuellement. Cela peut ne pas être pratique dans certains cas (par exemple, si vous avez beaucoup de colonnes dans la table de destination). Ainsi, l'approche ci-dessous peut être utile.

En fournissant le chemin et le nombre de colonnes de votre fichier csv, vous pouvez utiliser la fonction suivante pour charger votre table dans une table temporaire qui sera nommée comme target_table:

La ligne supérieure est supposée avoir les noms de 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
Salut Mehmet, merci pour la réponse que vous avez postée, mais lorsque j'exécute votre code, j'obtiens le message d'erreur suivant: ERREUR: le schéma "données" n'existe pas
user2867432

user2867432 vous devez changer le nom du schéma que vous utilisez en conséquence (par exemple, public)
mehmet

Salut Mehmet, Merci pour la solution, c'est parfait, mais cela ne fonctionne que si l'utilisateur de la base de données postgres est superutilisateur, existe-t-il un moyen de le faire fonctionner sans superutilisateur?
Geeme

Geeme: lire "security definer" ici , mais je ne l'ai pas utilisé moi-même.
mehmet

Belle réponse! Je ne vais pas trop générique dans mon code pour la lisibilité pour les autres.
Manohar Reddy Poreddy le

19

Comme Paul l'a mentionné, l'importation fonctionne dans pgAdmin:

clic droit sur la table -> importer

sélectionner le fichier local, le format et le codage

voici une capture d'écran de l'interface graphique allemande pgAdmin:

interface graphique d'importation pgAdmin

chose similaire que vous pouvez faire avec DbVisualizer (j'ai une licence, je ne suis pas sûr de la version gratuite)

clic droit sur une table -> Importer les données d'une table ...

Interface graphique d'importation de DbVisualizer


2
DBVisualizer a pris 50 secondes pour importer 1400 lignes avec trois champs - et j'ai dû tout restituer d'une chaîne à ce qu'elle était censée être.
Noumenon

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

10
  1. créer d'abord une table

  2. Utilisez ensuite la commande copy pour copier les détails du tableau:

copiez nom_table (C1, C2, C3 ....)
de 'chemin vers votre fichier csv' délimiteur ',' en-tête csv;

Merci


3
Comment n'est-ce pas la réponse acceptée? Pourquoi devrais-je écrire un script python alors que la base de données a déjà une commande pour le faire?
Wes


8

Expérience personnelle avec PostgreSQL, toujours en attente d'un moyen plus rapide.

1. Créez d'abord le squelette de la table si le fichier est stocké localement:

    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. Lorsque le \ path \ xxx.csv se trouve sur le serveur, postgreSQL n'a pas l'autorisation d'accéder au serveur, vous devrez importer le fichier .csv via la fonctionnalité intégrée pgAdmin.

Cliquez avec le bouton droit sur le nom de la table, choisissez importer.

entrez la description de l'image ici

Si vous rencontrez toujours des problèmes, veuillez consulter ce didacticiel. http://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/


6

Comment importer des données de fichier CSV dans une table PostgreSQL?

pas:

  1. Besoin de connecter la base de données postgresql dans le terminal

    psql -U postgres -h localhost
  2. Besoin de créer une base de données

    create database mydb;
  3. Besoin de créer un utilisateur

    create user siva with password 'mypass';
  4. Connectez-vous avec la base de données

    \c mydb;
  5. Besoin de créer un schéma

    create schema trip;
  6. Besoin de créer une table

    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. Importez les données du fichier csv dans 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. Trouver les données de table données

    select * from trip.test;

5

À mon humble avis , le moyen le plus pratique est de suivre " Importer des données CSV dans postgresql, la manière confortable ;-) ", en utilisant csvsql de csvkit , qui est un package python installable via pip.


3
La pourriture des liens est vorace! L'article auquel vous avez lié ne fonctionne plus, ce qui me met mal à l'aise :(
chbrown

vous voudrez peut-être mentionner que son py.
mountainclimber

1
Pour moi, j'obtiens une erreur MemoryError si j'essaie d'importer un grand fichier CSV, il semble donc qu'il ne diffuse pas.
DavidC

@DavidC Intéressant. Quelle est la taille de votre fichier? De combien de mémoire disposez-vous? Si elle ne marche pas courant comme il semble, je suggère Chunking les données avant l' insertion
sal

1
Le fichier avait une taille de 5 Go et j'ai 2 Go de mémoire. J'ai abandonné et j'ai finalement utilisé un script pour générer les commandes CREATE TABLE et COPY.
DavidC

3

En Python, vous pouvez utiliser ce code pour la création automatique de tables PostgreSQL avec des noms de colonnes:

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)

C'est aussi relativement rapide, je peux importer plus de 3,3 millions de lignes en 4 minutes environ.


2

Vous pouvez également utiliser pgfutter ou, encore mieux, pgcsv .

pgfutter est assez bogué, je recommande pgcsv.

Voici comment le faire avec pgcsv:

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

1

Si vous avez besoin d'un mécanisme simple pour importer du texte / analyser CSV multiligne, vous pouvez utiliser:

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) simplifie la connexion à une base de données, puis importe un fichier CSV pour le télécharger dans une base de données PostgreSQL. Il facilite également l'émission de requêtes, la récupération de données et le téléchargement d'ensembles de résultats au format CSV, JSON, SQL ou d'autres formats de données courants.

Il s'agit d'un outil de base de données multiplateforme FOSS pour les programmeurs SQL, les administrateurs de bases de données et les analystes qui prend en charge toutes les bases de données populaires: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc. Il s'agit d'un concurrent FOSS viable pour TOAD pour Postgres, TOAD pour SQL Server ou Toad pour Oracle.

Je n'ai aucune affiliation avec DBeaver. J'adore le prix (GRATUIT!) Et toutes les fonctionnalités, mais j'aimerais qu'ils ouvrent davantage cette application DBeaver / Eclipse et facilitent l'ajout de widgets d'analyse à DBeaver / Eclipse, plutôt que d'exiger des utilisateurs de payer l'abonnement annuel de 199 $ juste pour créer des graphiques et des diagrammes directement dans l'application. Mes compétences en codage Java sont rouillées et je n'ai pas envie de prendre des semaines pour réapprendre à créer des widgets Eclipse (seulement pour constater que DBeaver a probablement désactivé la possibilité d'ajouter des widgets tiers à DBeaver Community Edition.)

Les utilisateurs avancés de DBeaver qui sont des développeurs Java peuvent-ils fournir des informations sur les étapes de création de widgets d'analyse à ajouter à l'édition communautaire de DBeaver?


Il aurait été agréable de comprendre comment réellement utiliser DBeaver pour importer un fichier CSV. Quoi qu'il en soit, cela pourrait aider: dbeaver.com/docs/wiki/Data-transfer
umbe1987

0

Créez une table et disposez des colonnes requises qui sont utilisées pour créer une table dans un fichier csv.

  1. Ouvrez postgres et faites un clic droit sur la table cible que vous souhaitez charger et sélectionnez importer et mettre à jour les étapes suivantes dans la section des options de fichier

  2. Maintenant, parcourez votre fichier dans le nom de fichier

  3. Sélectionnez csv au format

  4. Encodage en ISO_8859_5

Maintenant, allez à Misc. options et vérifiez l'en-tête et cliquez sur importer.


0

J'ai créé un petit outil qui importe des csvfichiers dans PostgreSQL super facile, juste une commande et il créera et remplira les tables, malheureusement, pour le moment, tous les champs créés automatiquement utilisent le type TEXT

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

L'outil peut être trouvé sur https://github.com/eduardonunesp/csv2pg


Vous avez créé un outil distinct pour l'équivalent de psql -h 192.168.99.100 -U postgres mydatabase -c "COPY users FROM 'users.csv' DELIMITER ';' CSV"? Je suppose que la partie où il crée la table est agréable, mais comme chaque champ est du texte, il n'est pas super utile
GammaGames

1
Ops, merci pour les avertissements. Oui, je l'ai fait, eh bien cela n'a pris que quelques heures et j'ai appris des trucs sympas dans Go et pq et l'API de base de données dans Go.
Eduardo Pereira
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.