Como importar dados do arquivo CSV para uma tabela do PostgreSQL?

601

Como posso escrever um procedimento armazenado que importa dados de um arquivo CSV e preenche a tabela?

vardhan
fonte
18
Por que um procedimento armazenado? COPY faz o truque
Frank Heikens
1
Eu tenho uma interface de usuário que carrega o arquivo CSV, para ligar esta eu preciso o procedimento armazenado que realmente copia os dados do arquivo cvs
vardhan
3
você poderia elaborar como usar a COPY?
vardhan
17
Bozhidar Batsov já te dei um link para um exemplo, o fino manual também poderia ajudar: postgresql.org/docs/8.4/interactive/sql-copy.html
Frank Heikens
5
Manual atual: postgresql.org/docs/current/static/sql-copy.html
Basil Bourque

Respostas:

775

Dê uma olhada neste pequeno artigo .


Solução parafraseada aqui:

Crie sua tabela:

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

Copie dados do seu arquivo CSV para a tabela:

COPY zip_codes FROM '/path/to/csv/ZIP_CODES.txt' WITH (FORMAT csv);
Bozhidar Batsov
fonte
46
na verdade, use \ copy faria o mesmo truque se você não tiver acesso de superusuário; ele reclama no meu Fedora 16 ao usar o COPY com uma conta não raiz.
asksw0rder
81
DICA: você pode indicar quais colunas você tem no CSV usando zip_codes (col1, col2, col3). As colunas devem estar listadas na mesma ordem em que aparecem no arquivo.
David Pelaez
6
@ askw0rder \ copy tem a mesma sintaxe? bcoz eu estou recebendo um erro de sintaxe com \ copiar
JhovaniC
6
Devo incluir a linha do cabeçalho?
bernie2436
116
Você pode facilmente incluir a linha de cabeçalho - basta adicionar cabeçalho no opções: 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 você não tem permissão para usar COPY (que funciona no servidor db), poderá usá-lo \copy(que funciona no cliente db). Usando o mesmo exemplo que Bozhidar Batsov:

Crie sua tabela:

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

Copie dados do seu arquivo CSV para a tabela:

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

Você também pode especificar as colunas para ler:

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

Consulte a documentação para COPY :

Não confunda COPY com a instrução psql \ copy. \ copy chama COPY FROM STDIN ou COPY TO STDOUT e, em seguida, busca / armazena os dados em um arquivo acessível ao cliente psql. Portanto, a acessibilidade do arquivo e os direitos de acesso dependem do cliente e não do servidor quando \ copy é usado.

e observe:

Para colunas de identidade, o comando COPY FROM sempre gravará os valores da coluna fornecidos nos dados de entrada, como a opção INSERIR OVERRIDING SYSTEM VALUE.

bjelli
fonte
\ copy eleitores (ZIP, CITY) FROM '/Users/files/Downloads/WOOD.TXT' DELIMITER ',' CSV HEADER; ERRO: dados extras após a última coluna esperada CONTEXTO: COPY eleitores, linha 2: "OH0012781511,87,26953, CASA DE CASA, SHERRY, LEIGH ,, 11/26 / 1965,08 / 19/1988, 211 N GARFIELD ST, BLOOMD ... "
JZ.
@JZ. Eu tive um erro semelhante. Foi porque eu tinha colunas extras em branco. Verifique seu csv e se você tiver colunas em branco, esse pode ser o motivo.
Alex Bennett
5
Isso é um pouco enganador: a diferença entre COPYe \copyé muito mais do que apenas permissões, e você não pode simplesmente adicionar um `` para fazê-lo funcionar magicamente. Veja a descrição (no contexto da exportação) aqui: stackoverflow.com/a/1517692/157957
IMSoP
@IMSoP: Você está certo, eu adicionei uma menção de servidor e cliente para esclarecer
bjelli
@bjelli é \ copy mais lento que copiar? Eu tenho um arquivo de 1,5 MB e uma instância db.m4.large no RDS e já faz horas que esse comando de cópia está em execução (pelo menos 3).
2828 Sebastian
79

Uma maneira rápida de fazer isso é com a biblioteca pandas Python (a versão 0.15 ou superior funciona melhor). Isso tratará da criação das colunas para você - embora, obviamente, as escolhas feitas para os tipos de dados possam não ser o que você deseja. Se isso não der certo, você sempre poderá usar o código 'create table' gerado como modelo.

Aqui está um exemplo simples:

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)

E aqui está um código que mostra como definir várias opções:

# 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
fonte
6
Além disso, o if_existsparâmetro pode ser configurado para substituir ou acrescentar a uma tabela existente, por exemplo,df.to_sql("fhrs", engine, if_exists='replace')
joelostblom
1
nome de usuário e senha: é necessário criar o Login e atribuir o banco de dados ao usuário. Se usos pgAdmin, em seguida, criar "papel Login / Grupo" usando GUI
Somnath Kadam
9
O Pandas é uma maneira super lenta de carregar no sql (arquivos vs csv). Pode ser ordens de magnitude mais lenta.
User48956 4/04
Essa pode ser uma maneira de gravar dados, mas é super lenta mesmo com lotes e bom poder de computação. Usar CSVs é uma boa maneira de conseguir isso.
Ankit Singh
df.to_sql()é realmente lento, você pode usar d6tstack.utils.pd_to_psql()a partir d6tstack ver comparação de desempenho
citynorman
30

Você também pode usar o pgAdmin, que oferece uma GUI para fazer a importação. Isso é mostrado neste tópico SO . A vantagem de usar o pgAdmin é que ele também funciona para bancos de dados remotos.

Assim como as soluções anteriores, você precisaria já ter sua tabela no banco de dados. Cada pessoa tem sua própria solução, mas o que eu costumo fazer é abrir o CSV no Excel, copiar os cabeçalhos, colar especial com transposição em uma planilha diferente, colocar o tipo de dados correspondente na próxima coluna e copiar e colar em um editor de texto juntamente com a consulta de criação de tabela SQL apropriada, da seguinte maneira:

CREATE TABLE my_table (
    /*paste data from Excel here for example ... */
    col_1 bigint,
    col_2 bigint,
    /* ... */
    col_n bigint 
)
Paulo
fonte
1
pls mostrar um par de linhas de amostra de seus dados colados
dcorking
29

A maioria das outras soluções aqui exige que você crie a tabela antecipadamente / manualmente. Isso pode não ser prático em alguns casos (por exemplo, se você tiver muitas colunas na tabela de destino). Portanto, a abordagem abaixo pode ser útil.

Fornecendo o caminho e a contagem de colunas do seu arquivo csv, você pode usar a seguinte função para carregar sua tabela em uma tabela temporária denominada como target_table:

Presume-se que a linha superior tenha os nomes das colunas.

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
fonte
1
Oi Mehmet, obrigado pela resposta que você postou, mas quando eu executar o código eu recebo a seguinte mensagem de erro: Erro: "dados" de esquema não existe
user2867432
user2867432 você precisa nome do esquema mudança que você usa em conformidade (por exemplo, public)
mehmet
Oi Mehmet, Obrigado pela solução, é perfeito, mas Isso funciona apenas se o usuário do DB do postgres for superusuário, existe alguma maneira de fazê-lo funcionar sem superusuário?
Geeme
Geeme: leia "definidor de segurança" aqui , mas eu não o usei.
mehmet
Bela resposta! Eu não estou indo muito genérico embora no meu código para facilitar a leitura para os outros.
Manohar Reddy Poreddy 15/01
19

Como Paulo mencionou, a importação funciona no pgAdmin:

clique com o botão direito na tabela -> importar

selecione o arquivo local, formato e codificação

aqui está uma captura de tela alemã da pgAdmin GUI:

GUI de importação do pgAdmin

coisa semelhante que você pode fazer com o DbVisualizer (eu tenho uma licença, não tenho certeza da versão gratuita)

clique com o botão direito do mouse em uma tabela -> Importar Dados da Tabela ...

GUI de importação do DbVisualizer

Andreas L.
fonte
2
O DBVisualizer levou 50 segundos para importar 1400 linhas com três campos - e eu tive que converter tudo de volta de uma String para o que deveria ser.
Noumenon
19
COPY table_name FROM 'path/to/data.csv' DELIMITER ',' CSV HEADER;
timxor
fonte
10
  1. crie uma tabela primeiro

  2. Em seguida, use o comando copy para copiar os detalhes da tabela:

copiar table_name (C1, C2, C3 ....)
do 'caminho para o arquivo csv' delimitador ',' cabeçalho csv;

obrigado

user9130085
fonte
3
Como essa não é a resposta aceita? Por que eu escreveria um script python quando o banco de dados já possui um comando para fazer isso?
Wes
8

Experiência pessoal com o PostgreSQL, ainda esperando por um caminho mais rápido.

1. Crie o esqueleto da tabela primeiro se o arquivo estiver armazenado 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 o \ path \ xxx.csv estiver no servidor, o postgreSQL não tem permissão para acessar o servidor, você precisará importar o arquivo .csv através da funcionalidade incorporada no pgAdmin.

Clique com o botão direito do mouse no nome da tabela, escolha importar.

insira a descrição da imagem aqui

Se você ainda tiver problemas, consulte este tutorial. http://www.postgresqltutorial.com/import-csv-file-into-posgresql-table/

flowera
fonte
6

Como importar dados do arquivo CSV para uma tabela do PostgreSQL?

passos:

  1. Precisa conectar o banco de dados postgresql no terminal

    psql -U postgres -h localhost
  2. Precisa criar banco de dados

    create database mydb;
  3. Precisa criar usuário

    create user siva with password 'mypass';
  4. Conectar-se ao banco de dados

    \c mydb;
  5. Precisa criar esquema

    create schema trip;
  6. Precisa criar tabela

    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 dados do arquivo csv para o 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. Encontre os dados da tabela fornecidos

    select * from trip.test;
sivamani
fonte
5

IMHO, a maneira mais conveniente é seguir " Importar dados CSV para o postgresql, da maneira mais confortável ;-) ", usando csvsql do csvkit , que é um pacote python instalável via pip.

sal
fonte
3
A podridão do link é voraz! O artigo ao qual você vinculou não funciona mais, o que me deixa desconfortável :(
chbrown 27/07
você pode mencionar que o dele é py.
mountainclimber
1
Para mim, recebo um MemoryError se tentar importar um CSV grande, para que pareça que não é transmitido.
DavidC
@DavidC Interesting. Qual é o tamanho do seu arquivo? Quanta memória você tem? Se isso não acontecer fluxo de como ele aparece, eu sugiro chunking os dados antes da inserção
sal
1
O arquivo tinha 5 GB de tamanho e eu tenho 2 GB de memória. Eu desisti e usei um script para gerar comandos CREATE TABLE e COPY no final.
DavidC
3

No Python, você pode usar este código para criação automática de tabela do PostgreSQL com nomes de colunas:

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)

Também é relativamente rápido, posso importar mais de 3,3 milhões de linhas em cerca de 4 minutos.

Marc
fonte
2

Você também pode usar pgfutter ou, melhor ainda, pgcsv .

pgfutter é um buggy, recomendo pgcsv.

Aqui está como fazer isso com o pgcsv:

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

Se você precisar de um mecanismo simples para importar de texto / analisar CSV multilinhas, poderá 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
fonte
1

O DBeaver Community Edition (dbeaver.io) facilita a conexão com um banco de dados e depois importa um arquivo CSV para upload para um banco de dados PostgreSQL. Também facilita a emissão de consultas, a recuperação de dados e o download de conjuntos de resultados para CSV, JSON, SQL ou outros formatos de dados comuns.

É uma ferramenta de banco de dados multi-plataforma FOSS para programadores, DBAs e analistas de SQL que suporta todos os bancos de dados populares: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc. É um concorrente viável do FOSS para o TOAD para Postgres, o TOAD para SQL Server ou o Toad para Oracle.

Não tenho afiliação com o DBeaver. Adoro o preço (GRATUITO!) E a funcionalidade completa, mas desejo que eles abram mais esse aplicativo DBeaver / Eclipse e facilitem a adição de widgets de análise ao DBeaver / Eclipse, em vez de exigir que os usuários paguem apenas US $ 199 por assinatura anual para criar gráficos e tabelas diretamente dentro do aplicativo. Minhas habilidades de codificação Java estão enferrujadas e não me apetece levar semanas para reaprender a criar widgets do Eclipse (apenas para descobrir que o DBeaver provavelmente desativou a capacidade de adicionar widgets de terceiros ao DBeaver Community Edition.)

Os usuários avançados do DBeaver, que são desenvolvedores de Java, podem fornecer algumas dicas sobre as etapas para criar widgets de análise para adicionar ao Community Edition do DBeaver?

Rich Lysakowski PhD
fonte
Seria bom entender como realmente usar o DBeaver para importar um arquivo CSV. De qualquer forma, isso pode ajudar: dbeaver.com/docs/wiki/Data-transfer
umbe1987 17/04
0

Crie a tabela e tenha colunas necessárias que são usadas para criar a tabela no arquivo csv.

  1. Abra o postgres e clique com o botão direito na tabela de destino que você deseja carregar e selecione importar e Atualize as seguintes etapas na seção de opções de arquivo

  2. Agora procure seu arquivo no nome do arquivo

  3. Selecione csv no formato

  4. Codificação como ISO_8859_5

Agora vá para Misc. opções e verifique o cabeçalho e clique em importar.

suriruler
fonte
0

Criei uma pequena ferramenta que importa csvarquivos para o PostgreSQL super fácil, apenas um comando e ele criará e preencherá as tabelas, infelizmente, no momento todos os campos criados automaticamente usam o tipo TEXT

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

A ferramenta pode ser encontrada em https://github.com/eduardonunesp/csv2pg

Eduardo Pereira
fonte
Você criou uma ferramenta separada para o equivalente a psql -h 192.168.99.100 -U postgres mydatabase -c "COPY users FROM 'users.csv' DELIMITER ';' CSV"? Eu acho que a parte onde ele cria a tabela é bom, mas uma vez que cada campo é um texto que não é super útil
GammaGames
1
Ops, obrigado pelo aviso. Sim, eu fiz isso, bem, demorou apenas algumas horas e aprendi coisas legais no Go and pq e API de banco de dados no Go.
Eduardo Pereira