CSV dosyasında başlıklarla birlikte CSV dosyasından PostgreSQL tablosuna nasıl kopyalanır?


93

Bir CSV dosyasını Postgres tablosuna kopyalamak istiyorum. Bu tabloda yaklaşık 100 sütun var, bu yüzden mecbur kalmazsam onları yeniden yazmak istemiyorum.

\copy table from 'table.csv' delimiter ',' csv;Komutu kullanıyorum ama bir tablo oluşturmadan alıyorum ERROR: relation "table" does not exist. Boş bir tablo eklersem hata almam ama hiçbir şey olmuyor. Bu komutu iki veya üç kez denedim ve çıktı veya mesaj yoktu, ancak PGAdmin aracılığıyla kontrol ettiğimde tablo güncellenmedi.

Yapmaya çalıştığım gibi başlıkları içeren bir tabloyu içe aktarmanın bir yolu var mı?


2
Masanızın adı tablemı? Çok kafa karıştırıcı. Tablo var mı yoksa CSV'ye dayalı olarak oluşturmak mı istiyorsunuz? (yapamazsınız)
wildplasser

1
Pekala, ona başka bir isim verdim ama bu örnek için tablo diyelim. Var olan ve olmadan denedim, \copy table(column1, column2, ...) from 'table.csv' delimiter ',' csv;şanssız da yapmaya çalıştım . İdeal olarak tablo yalnızca CSV aracılığıyla oluşturulabilir ve bu dosyadaki başlıkları kullanabilir.
Stanley Cup Phil


2
Büyük bir csv'yi postgres tablosuna dönüştürmeyi planlayanlar için sadece bir uyarı - postgres tek bir tabloda 1600 sütunla sınırlandırılmıştır. Tabloları 1600 sütun büyüklüğünde olanlara bölemez ve sonra onları birleştiremezsiniz. Db'yi yeniden tasarlamanız gerekiyor.
Achekroud

Python sizin için mevcutsa, d6tstack'i kullanabilirsiniz . Şema değişikliklerini de halleder.
citynorman

Yanıtlar:


135

Bu işe yaradı. İlk satırda sütun adları vardı.

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

5
Bence bu komutla ilgili sorun, DB süper kullanıcısı olmanız gerektiğidir. \ copy normal kullanıcı olarak da çalışıyor
Exocom

29
COPYtablo oluşturmaz veya ona sütun eklemez, mevcut sütunlarıyla mevcut bir tabloya satır ekler. Muhtemelen soran kişi ~ 100 sütunun yaratılmasını otomatikleştirmek istemektedir ve COPYen azından PG 9.3'ten itibaren bu işlevselliğe sahip değildir.
Daniel Vérité

2
@Exocom iyi yakaladı. Kullandığım postgres sistemlerinde DB'ler için asla bir yönetici veya süper kullanıcı olmadığım için (pgadmin beni kullandığım veritabanlarının sahibi yapar ve bana sınırlı ayrıcalıklar / roller verir) "\ COPY" kullanmış olmalıyım. Şerefe
G. Cito

2
@Daniel Kullanıcının tablosunun zaten var olduğunu ve ihtiyaç duydukları tüm sütunlara sahip olduklarını ve basitçe veri yapmak istediklerini anladım ADD.
G. Cito

Got syntax error at or near "HEADER" LINE 2: delimiter ',' CSV HEADERaws kırmızıya kayma üzerinde.
Mithril

24

Python kitaplığıyla pandas, bir csv dosyasından kolayca sütun adları oluşturabilir ve veri türlerini çıkarabilirsiniz.

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)

if_existsParametresi, örneğin değiştirmek veya varolan bir tabloya ekleme ayarlanabilir df.to_sql('pandas_db', engine, if_exists='replace'). Bu, ek girdi dosyası türleri için de işe yarar, buradaki ve buradaki belgeler .


1
Pd.DataFrame.from_csv'nin bana daha az sorun çıkardığını görüyorum, ancak bu yanıt bunu yapmanın en kolay yolu, IMO.
Brock

Doğru, pd.read_excelyerine neden yazdığımdan emin değilim pd.read_csv. Cevabı güncelledim.
joelostblom

1
Bu, büyük bir csv içeren tabloyu önceden oluşturmak istemediğinizde harika bir çözümdür. Yine de bir uyarı - postgres bir tabloda yalnızca 1600 sütun alabilir. Görünüşe göre diğer DB motorları daha fazlasına izin verecek. Bu kadar çok sütuna sahip olmak görünüşte zayıf SQL formudur, ancak bu fikir birliği henüz epidemiyolojiye süzülmemiştir.
Achekroud

1
Varsayılan df.to_sql()olarak ÇOK YAVAŞtır , bunu hızlandırmak için d6tstack kullanabilirsiniz . Şema değişikliklerini de halleder.
citynorman

13

İzinsiz terminal tarafından alternatif

NOTLAR de pg dokümantasyon söz hakkından

Yol, istemcinin çalışma dizinine değil, sunucu işleminin çalışma dizinine (normalde kümenin veri dizini) göre yorumlanacaktır.

Yani, gerally, kullanmak psqlveya herhangi bir istemci, yerel bir sunucuda bile, problemleriniz var ... Ve eğer diğer kullanıcılar için COPY komutunu ifade ediyorsanız, örn. Github README'de okuyucunun sorunları olacaktır ...

İstemci izinleriyle göreli yolu ifade etmenin tek yolu STDIN kullanmaktır ,

STDIN veya STDOUT belirtildiğinde, veriler istemci ve sunucu arasındaki bağlantı yoluyla iletilir.

burada hatırlandığı gibi :

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

3

Bu işlevi bir süredir sorunsuz kullanıyorum. Sadece csv dosyasında bulunan sayı sütunlarını sağlamanız yeterlidir ve ilk satırdan başlık adlarını alacak ve sizin için tabloyu oluşturacaktır:

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;

senin set schema 'data';için durum ne ise değiştirmeyi unutma
mehmet

0

Sen kullanabilirsiniz d6tstack sizin için tablo oluşturur ve bir ) hızlı pd.to_sql daha ( o yerli DB ithalat komutları kullanması nedeniyle. Postgres'in yanı sıra MYSQL ve MS SQL'i de destekler.

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')

Ayrıca, birden çok CSV'yi içe aktarmak, veri şeması değişikliklerini çözmek ve / veya db'ye yazmadan önce pandalarla ön işlem yapmak (örneğin tarihler için) için kullanışlıdır, örnekler not defterinde daha fazla aşağıya bakın

d6tstack.combine_csv.CombinerCSV(glob.glob('*.csv'), 
    apply_after_read=apply_fun).to_psql_combine(uri_psql, 'table')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.