2015-11-21 171 views
0

我有一個CSV文件,其中引用了所有條目,即帶有開頭和結尾的引號。當我導入到使用copy_from數據庫,數據庫表中包含的數據報價,那裏有一個空項我只得到即「」列項,如下psycopg2.copy_from:從CSV導入時從文本中刪除引號

[Bad Quoted text[1]

看到的報價是否有一種告訴copy_from忽略引號的方法,以便在我導入文件時文本週圍沒有引號,並且空條目被轉換爲Null,如下所示?

Expected data entries

這裏是我的代碼:

with open(source_file_path) as inf: 
    cursor.copy_from(inf, table_name, columns=column_list, sep=',', null="None") 

UPDATE

我仍然沒有得到解決以上,但得到該文件導入我的緣故繼續寫下原始SQL代碼,並在SQLAlchemy連接和Pyscopg2的遊標中執行它,如下所示,它們都刪除引號,並在有空條目的地方放置Null。

sql = "COPY table_name (col1, col2, col3, col4) FROM '{}' DELIMITER ',' CSV HEADER".format(csv_file_path) 

SQL鍊金:

conn = engine.connect() 
trans = conn.begin() 
conn.execute(sql) 
trans.commit() 
conn.close() 

Psycopg2:

conn = psycopg2.connect(pg_conn_string) 
conn.set_isolation_level(0) 
cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) 
cursor = conn.cursor() 
cursor.execute(sql) 

儘管仍然希望在copy_from功能會工作,如果上述兩個同樣的速度,現在我想知道如copy_from,如果是的話,哪兩個更快?

回答

0

也許更好的方法是使用內置的CSV庫來讀取CSV文件並將行傳輸到數據庫。 UNIX的哲學「推行一件事並做得好」的推論是使用適當的工具(專門的工具)進行工作。 CSV庫的優點在於,您可以定製如何讀取CSV文件(如引用字符和跳過初始行)的選項(請參閱documentation)。

假設有兩列一個簡單的CSV文件:一個整數 「ID」,並引用字符串 「國家代碼」:

"ID", "Country Code" 
1, "US" 
2, "UK" 

和聲明SQLAlchemy的目標表:

from sqlalchemy import create_engine, Column, Integer, String 
from sqlalchemy.ext.declarative import declarative_base 


engine = create_engine("postgresql+psycopg2://<REMAINDER_OF_YOUR_ENGINE_STRING>") 
Base = declarative_base(bind=engine) 

class CountryTable(Base): 
    __tablename__ = 'countries' 

    id = Column(Integer, primary_key=True) 
    country = Column(String) 

你可以通過以下方式傳輸數據:

import csv 

from sqlalchemy.orm import sessionmaker 

from your_model_module import engine, CountryTable 


Session = sessionmaker(bind=engine) 
with open("path_to_your.csv", "rb") as f: 
    reader = csv.DictReader(f) 
    session = Session() 
    for row in reader: 
     country_record = CountryTable(id=row["ID"], country=row["Country Code"]) 
     session.add(country_record) 
     session.commit() 
    session.close() 

此解決方案比一行更長.copy_from方法但它可以讓您更好地進行控制,而無需深入瞭解代碼/理解包裝器文檔或便利功能(如.copy_from)的文檔。您可以指定要傳輸的選定列,並在行級別處理異常,因爲數據是通過提交逐行傳輸的。行可以批量轉移與單個提交過:

with open("path_to_your.csv", "rb") as f: 
    reader = csv.DictReader(f) 
    session = Session() 
    session.add_all([ 
     CountryTable(id=row["ID"], country=row["Country Code"]) for row in reader 
     ]) 
    session.commit() 
    session.close()  

爲不同方法的執行時間比較您的問題,使用timeit模塊(或相當的命令行命令)Python自帶。但請注意:it's better to be correct than fast


編輯:

我試圖找出其中,因爲我以前沒有使用過它.copy_from是編碼。原來是a psycopg2 specific convenience function。它不會100%支持閱讀CSV文件,但只能像對象一樣文件。適用於CSV的唯一定製參數是分隔符。它不理解引用字符。

+0

謝謝你。我廣泛使用CSV庫,但是當我需要控制每個列和行(單元格)時,尤其是在驗證數據時,我使用它。然而,在這種情況下,數據符合所有要求,並且它在多個14GB文件中,所以如果逐行讀取,那麼當一個簡單的「copy_from」花費幾分鐘時間來吞噬這些類型的文件時,就會是'浪費時間'。 – lukik