Psycopg2:将CSV数据复制到具有额外列值的

时间:2017-03-15 19:40:49

标签: python postgresql csv copy psycopg2

我使用copy_expert中的psycopg2方法将数据从CSV文件复制到postgresql表。我有这样的postgres表:

create table my_table (
  cola          text,
  colb          text,
  colc          text,
  cold          text,
  cole          text,
  colf          text,
  colg          text
)

包含类似前五列数据的CSV,如下所示:

cola,colb,colc,cold,cole
1,foo,a,10,vvv
2,bar,b,20,www
3,baz,c,30,xxx
4,boo,d,40,yyy
5,baa,e,50,zzz

我想复制前五列的CSV数据,同时还指定colfcolg的值(每行应具有colf和{{的相同值1}})。

我可以将前五列复制到我的表中,如下所示:

colg

如何使用python指定最后两列的值?我知道我可以在表DDL中指定默认值,如下所示:

conn = psycopg2.connect('dbname=name user=username')
cur = conn.cursor()
copy_sql = """
  copy my_table (cola, colb, colc, cold, cole)
  from stdin with
    csv
    header
    delimiter as ','
"""
from_csv = '/path/to/data.csv'
with open(from_csv, 'r') as f:
  cur.copy_expert(sql=copy_sql, file=f)
  conn.commit()
  cur.close()

但是我想使用python添加值,因为每个CSV上传都有自己的create table my_table ( cola text, colb text, colc text, cold text, cole text, colf text default 'foo', colg text default 'bar' ) colf值,这些值由我的python代码中的逻辑确定

1 个答案:

答案 0 :(得分:1)

通过首先将我需要的列添加到数据中,然后上传更新的数据,看起来有几种方法可以做到这一点。

使用petl包:

import psycopg2
from petl import fromcsv, addfield, todb

csv_file = '/path/to/data.csv'
table = fromcsv(csv_file)
table = addfield(table, 'colf', 'Some value')
table = addfield(table, 'colg', 'Another value')

conn = psycopg2.connect('dbname=test user=user')
todb(table, conn, 'my_table')

这在小数据上运行正常,但在大数据上却非常慢。 psycopg2 copy_fromcopy_expert命令似乎更快,因为它们使用postgresql批量复制。我首先将我的csv文件转换为copy_from pandas,然后使用dataframe复制我的数据:

import psycopg2
import pandas as pd
from StringIO import StringIO

csv_file = '/path/to/file'
df = pd.read_csv(csv_file)
df['colf'] = 'My value'
df['colg'] = 'Foobar'

为了使用psycopg2 copy_命令,我需要将dataframe转换为具有read()readline()的类似文件的对象方法,我可以使用StringIO

buf = StringIO()
df.to_csv(buf, header=False, index=False)
buf.pos = 0

请注意,您需要将缓冲区的pos设置为0,因为pandas.to_csv似乎默认将pos设置为结尾。有关说明,请参阅this SO answer

然后我可以复制该缓冲区对象:

conn = psycopg2.connect('dbname=test user=user')
cur = conn.cursor()
cur.copy_from(buf, 'my_table', sep=',')
conn.commit()
cur.close()