¿Cómo importar datos de archivos CSV en una tabla PostgreSQL?

602

¿Cómo puedo escribir un procedimiento almacenado que importe datos de un archivo CSV y complete la tabla?

vardhan
fuente
18
¿Por qué un procedimiento almacenado? COPY hace el truco
Frank Heikens
1
Tengo una interfaz de usuario que carga el archivo csv, para conectar esto necesito el procedimiento almacenado que realmente copia los datos del archivo cvs
vardhan
3
¿podría explicar cómo usar la COPIA?
vardhan
17
Bozhidar Batsov ya le dio un enlace a un ejemplo, el buen manual también podría ayudar: postgresql.org/docs/8.4/interactive/sql-copy.html
Frank Heikens
55
Manual actual: postgresql.org/docs/current/static/sql-copy.html
Basil Bourque

Respuestas:

775

Echa un vistazo a este breve artículo .


Solución parafraseada aquí:

Crea tu mesa:

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

Copie los datos de su archivo CSV a la tabla:

COPY zip_codes FROM '/path/to/csv/ZIP_CODES.txt' WITH (FORMAT csv);
Bozhidar Batsov
fuente
46
realmente use \ copy haría el mismo truco si no tiene acceso de superusuario; se queja en mi Fedora 16 cuando uso COPY con una cuenta no root.
askw0rder
81
SUGERENCIA: puede indicar qué columnas tiene en el CSV utilizando los códigos postales (col1, col2, col3). Las columnas deben aparecer en el mismo orden en que aparecen en el archivo.
David Peláez
66
@ askw0rder ¿\ copy tiene la misma sintaxis? porque tengo un error de sintaxis con \ copy
JhovaniC
66
¿Debo incluir la fila del encabezado?
bernie2436
116
Puede incluir fácilmente la fila del encabezado: simplemente agregue HEADER en las opciones: 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 no tiene permiso para usar COPY(que funciona en el servidor db), puede usar \copyen su lugar (que funciona en el cliente db). Usando el mismo ejemplo que Bozhidar Batsov:

Crea tu mesa:

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

Copie los datos de su archivo CSV a la tabla:

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

También puede especificar las columnas para leer:

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

Consulte la documentación para COPIA :

No confunda COPY con la instrucción psql \ copy. \ copy invoca COPY FROM STDIN o COPY TO STDOUT, y luego recupera / almacena los datos en un archivo accesible para el cliente psql. Por lo tanto, la accesibilidad de los archivos y los derechos de acceso dependen del cliente en lugar del servidor cuando se usa \ copy.

y nota:

Para las columnas de identidad, el comando COPIAR DESDE siempre escribirá los valores de columna proporcionados en los datos de entrada, como la opción INSERTAR VALOR DE ANULACIÓN DEL SISTEMA.

bjelli
fuente
\ copiar votantes (ZIP, CITY) FROM '/Users/files/Downloads/WOOD.TXT' DELIMITER ',' CSV HEADER; ERROR: datos adicionales después de la última columna esperada CONTEXTO: COPIA de votantes, línea 2: "OH0012781511,87,26953, HOGAR, SHERRY, LEIGH ,, 11/26 / 1965,08 / 19/1988,, 211 N GARFIELD ST,, BLOOMD ... "
JZ.
@JZ. Tuve un error similar Fue porque tenía columnas extra en blanco. Verifique su csv y si tiene columnas en blanco, esa podría ser la razón.
alex bennett
55
Esto es algo engañoso: la diferencia entre COPYy \copyes mucho más que solo permisos, y no puede simplemente agregar un `` para que funcione mágicamente. Consulte la descripción (en el contexto de la exportación) aquí: stackoverflow.com/a/1517692/157957
IMSoP el
@IMSoP: tienes razón, agregué una mención de servidor y cliente para aclarar
bjelli
@bjelli es \ copy más lento que copy? Tengo un archivo de 1.5MB y una instancia db.m4.large en RDS y hace horas que este comando de copia se ha estado ejecutando (al menos 3).
Sebastian
79

Una forma rápida de hacerlo es con la biblioteca de pandas de Python (la versión 0.15 o superior funciona mejor). Esto manejará la creación de las columnas por usted, aunque obviamente las elecciones que hace para los tipos de datos podrían no ser lo que desea. Si no hace lo que quiere, siempre puede usar el código 'crear tabla' generado como plantilla.

Aquí hay un ejemplo 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)

Y aquí hay un código que le muestra cómo configurar varias opciones:

# 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
fuente
66
Además, el if_existsparámetro se puede configurar para reemplazar o agregar a una tabla existente, por ejemplodf.to_sql("fhrs", engine, if_exists='replace')
joelostblom
1
nombre de usuario y contraseña: es necesario crear un inicio de sesión y asignar DB al usuario. Si usa pgAdmin, cree el "rol de inicio de sesión / grupo" con GUI
Somnath Kadam
99
Pandas es una forma súper lenta de cargar en sql (vs archivos csv). Pueden ser órdenes de magnitud más lentas.
user48956
Esta podría ser una forma de escribir datos, pero es súper lento incluso con lotes y buena potencia de cómputo. Usar CSV es una buena manera de lograr esto.
Ankit Singh
df.to_sql()es realmente lento, puedes usarlo d6tstack.utils.pd_to_psql()desde d6tstack ver comparación de rendimiento
citynorman
30

También puede usar pgAdmin, que ofrece una GUI para importar. Eso se muestra en este hilo SO . La ventaja de usar pgAdmin es que también funciona para bases de datos remotas.

Sin embargo, al igual que las soluciones anteriores, ya debería tener su tabla en la base de datos. Cada persona tiene su propia solución, pero lo que generalmente hago es abrir el archivo CSV en Excel, copiar los encabezados, pegar especiales con transposición en una hoja de trabajo diferente, colocar el tipo de datos correspondiente en la siguiente columna y luego copiarlo y pegarlo en un editor de texto junto con la consulta de creación de la tabla SQL adecuada de la siguiente manera:

CREATE TABLE my_table (
    /*paste data from Excel here for example ... */
    col_1 bigint,
    col_2 bigint,
    /* ... */
    col_n bigint 
)
Pablo
fuente
1
los pls muestran un par de filas de muestra de sus datos pegados
dcorking
29

La mayoría de las otras soluciones aquí requieren que cree la tabla por adelantado / manualmente. Esto puede no ser práctico en algunos casos (por ejemplo, si tiene muchas columnas en la tabla de destino). Entonces, el siguiente enfoque puede ser útil.

Al proporcionar la ruta y el recuento de columnas de su archivo csv, puede usar la siguiente función para cargar su tabla en una tabla temporal que se denominará como target_table :

Se supone que la fila superior tiene los nombres de columna.

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
fuente
1
Hola Mehmet, gracias por la respuesta que publicaste, pero cuando ejecuto tu código recibo el siguiente mensaje de error: ERROR: el esquema "datos" no existe
usuario2867432
user2867432 necesita cambiar el nombre de esquema que usa en consecuencia (por ejemplo, public)
mehmet
Hola Mehmet, gracias por la solución, es perfecto, pero esto funciona solo si el usuario de Postgres DB es superusuario, ¿hay alguna forma de hacerlo funcionar sin superusuario?
Geeme
Geeme: lea "definidor de seguridad" aquí , pero no lo he usado yo mismo.
mehmet
Hermosa respuesta! Sin embargo, no voy a ser demasiado genérico en mi código para que otros puedan leerlo.
Manohar Reddy Poreddy
19

Como mencionó Paul, la importación funciona en pgAdmin:

haga clic derecho en la tabla -> importar

seleccionar archivo local, formato y codificación

Aquí hay una captura de pantalla alemana pgAdmin GUI:

GUI de importación pgAdmin

algo similar que puede hacer con DbVisualizer (tengo una licencia, no estoy seguro acerca de la versión gratuita)

haga clic derecho en una tabla -> Importar datos de tabla ...

GUI de importación de DbVisualizer

Andreas L.
fuente
2
DBVisualizer tardó 50 segundos en importar 1400 filas con tres campos, y tuve que devolver todo de una Cadena a lo que se suponía que era.
Noumenon
19
COPY table_name FROM 'path/to/data.csv' DELIMITER ',' CSV HEADER;
Timxor
fuente
10
  1. crear una tabla primero

  2. Luego use el comando copiar para copiar los detalles de la tabla:

copie nombre_tabla (C1, C2, C3 ....)
de 'ruta a su archivo csv' delimitador ',' encabezado csv;

Gracias

usuario9130085
fuente
3
¿Cómo es que esta no es la respuesta aceptada? ¿Por qué escribiría un script de Python cuando la base de datos ya tiene un comando para hacer esto?
Wes
8

Experiencia personal con PostgreSQL, aún esperando una forma más rápida.

1. Cree el esqueleto de la tabla primero si el archivo se almacena 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. Cuando \ path \ xxx.csv está en el servidor, postgreSQL no tiene permiso para acceder al servidor, deberá importar el archivo .csv a través de la funcionalidad integrada pgAdmin.

Haga clic derecho en el nombre de la tabla, elija importar.

ingrese la descripción de la imagen aquí

Si aún tiene problemas, consulte este tutorial. http://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/

Flowera
fuente
6

¿Cómo importar datos de archivos CSV en una tabla PostgreSQL?

pasos:

  1. Necesita conectar la base de datos postgresql en la terminal

    psql -U postgres -h localhost
  2. Necesito crear una base de datos

    create database mydb;
  3. Necesito crear usuario

    create user siva with password 'mypass';
  4. Conectar con la base de datos

    \c mydb;
  5. Necesito crear un esquema

    create schema trip;
  6. Necesito crear tabla

    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. Importar datos de archivos csv a 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. Encuentra los datos de la tabla dada

    select * from trip.test;
sivamani
fuente
5

En mi humilde opinión, la forma más conveniente es seguir " Importar datos CSV en postgresql, la forma cómoda ;-) ", utilizando csvsql de csvkit , que es un paquete de Python instalable a través de pip.

sal
fuente
3
Link rot es voraz! El artículo al que se vinculó ya no funciona, lo que me hace sentir incómodo :(
chbrown
es posible que desee mencionar que es py.
mountainclimber
1
Para mí obtengo un MemoryError si intento importar un CSV grande para que parezca que no se transmite.
DavidC
@DavidC Interesante. ¿Qué tan grande es tu archivo? ¿Cuanta memoria tienes? Si no se transmite como parece, sugiero agrupar los datos antes de la inserción
sal
1
El archivo tenía un tamaño de 5 GB y tengo 2 GB de memoria. Me di por vencido y utilicé un script para generar comandos CREATE TABLE y COPY al final.
DavidC
3

En Python, puede usar este código para la creación automática de tablas PostgreSQL con nombres de columna:

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)

También es relativamente rápido, puedo importar más de 3.3 millones de filas en aproximadamente 4 minutos.

Bagazo
fuente
2

También puede usar pgfutter o, mejor aún, pgcsv .

pgfutter es bastante defectuoso, recomendaría pgcsv.

Aquí se explica cómo hacerlo con pgcsv:

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

Si necesita un mecanismo simple para importar texto / analizar CSV multilínea, puede usar:

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

Lukasz Szozda
fuente
1

DBeaver Community Edition (dbeaver.io) hace que sea trivial conectarse a una base de datos, luego importar un archivo CSV para cargarlo en una base de datos PostgreSQL. También facilita la emisión de consultas, la recuperación de datos y la descarga de conjuntos de resultados a CSV, JSON, SQL u otros formatos de datos comunes.

Es una herramienta de base de datos multiplataforma FOSS para programadores SQL, DBA y analistas que admite todas las bases de datos populares: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc. Es un competidor viable de FOSS para TOAD para Postgres, TOAD para SQL Server o Toad para Oracle.

No tengo afiliación con DBeaver. Me encanta el precio (¡GRATIS!) Y la funcionalidad completa, pero desearía que abrieran más esta aplicación DBeaver / Eclipse y facilitaran agregar widgets de análisis a DBeaver / Eclipse, en lugar de exigir a los usuarios que paguen la suscripción anual de $ 199 solo para crear gráficos y cuadros directamente dentro de la aplicación. Mis habilidades de codificación de Java están oxidadas y no tengo ganas de tomarme semanas para volver a aprender a construir widgets de Eclipse (solo para descubrir que DBeaver probablemente ha deshabilitado la capacidad de agregar widgets de terceros a DBeaver Community Edition).

¿Pueden los usuarios avanzados de DBeaver que son desarrolladores de Java proporcionar alguna información sobre los pasos para crear widgets de análisis para agregar a la Edición comunitaria de DBeaver?

Rich Lysakowski PhD
fuente
Hubiera sido bueno entender cómo usar DBeaver para importar un archivo CSV. De todos modos, esto podría ayudar: dbeaver.com/docs/wiki/Data-transfer
umbe1987
0

Cree una tabla y tenga las columnas necesarias que se utilizan para crear la tabla en el archivo csv.

  1. Abra postgres y haga clic derecho en la tabla de destino que desea cargar y seleccione importar y actualice los siguientes pasos en la sección de opciones de archivo

  2. Ahora busque su archivo en nombre de archivo

  3. Seleccione csv en formato

  4. Codificación como ISO_8859_5

Ahora ir a misceláneos opciones y verifique el encabezado y haga clic en importar.

suriruler
fuente
0

Creé una pequeña herramienta que importa csvarchivos en PostgreSQL súper fácil, solo un comando y creará y completará las tablas, desafortunadamente, en este momento, todos los campos creados automáticamente usan el tipo TEXT

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

La herramienta se puede encontrar en https://github.com/eduardonunesp/csv2pg

Eduardo Pereira
fuente
Hiciste una herramienta separada para el equivalente de psql -h 192.168.99.100 -U postgres mydatabase -c "COPY users FROM 'users.csv' DELIMITER ';' CSV" ? Supongo que la parte donde crea la tabla es agradable, pero como cada campo es texto, no es súper útil
GammaGames
1
Ops, gracias por el aviso. Sí, lo hice, bueno, me llevó unas pocas horas y aprendí cosas interesantes en Go y pq y API de base de datos en Go.
Eduardo Pereira