用于批量插入的 psycopg2 格式

psycopg2 formatting for bulk insertion

我以这种方式插入行,data 是多个 fieldname: fieldvalue 项的字典:

def add_row(self, data, table): #data is a dictionary
    columns = data.keys()
    values = []

    for column in columns:
        if isinstance(data[column], list): #checking for json values
            values.append(Json(data[column])) 
        elif isinstance(data[column], dict):
            values.append(Json(data[column])) 
        else:
            values.append(data[column])
    insert_statement = 'insert into %s ' % table + '(%s) values %s'
    self.cur.execute(insert_statement, (AsIs(','.join(columns)), tuple(values)))
    self.conn.commit()
    print "added %s" % table

但现在我想批量插入行以提高性能并减少 I/O 使用。问题是我找不到正确的方法。以下函数抛出(data 是上述项目的列表):

psycopg2.ProgrammingError: syntax error at or near "["
LINE 1: ...,category_id,initial_quantity,base_price) VALUES ([u'Entrega...
def add_row_bulk(self, data, table): #data is a dictionary
    columns = data[0].keys()
    value_rows = []
    for e in data:
        columns = e.keys()
        values = []

        for column in columns:
            if isinstance(e[column], list): #checking for json values
                values.append(Json(e[column])) 
            elif isinstance(e[column], dict):
                values.append(Json(e[column])) 
            else:
                values.append(e[column])
        value_rows.append(AsIs(values))

    cols = (AsIs(','.join(columns)))
    query = self.cur.mogrify("INSERT INTO item (%s) VALUES %s", (cols, tuple(value_rows)))
    self.cur.execute(query) 
    self.conn.commit()
    print "added %s" % table

您的 SQL 生成代码有几个问题。

首先,AsIs(values) 不会像您希望的那样 mogrify 进入值行。测试了一下,好像相当于AsIs(str(values))。这就是您在抛出的错误中看到的输出。

在您的工作示例中起作用的是在单独的值元组上使用 mogrify。将 tuple(values) 添加到 value_rows,而不是 AsIs(values)

其次,要指定在一个插入语句中插入多行的值,您需要SQL syntax similar to the following:

... VALUES (1, 'x'), (2, 'y'), (3, 'z')

请注意,值列表的列表周围没有 ( )。没有什么(据我所知)会神奇地 mogrify 进入这样的列表。当然 tuple 不会。

因此您需要执行以下操作:

self.cur.mogrify('INSERT INTO item (%s) VALUES %s,%s,%s,%s',
                 (cols, value_row1, value_row2, value_row3, value_row4))

这意味着您需要做更多的工作来生成 mogrify 的两个参数,因为事先不知道行数。要生成第一个参数,您可以执行以下操作:

'INSERT INTO item (%s) VALUES ' + ','.join(['%s'] * len(value_rows))

并且第二个参数需要是第一个值为 cols 的序列,其余为 value_rows 的内容。一种方法:

[cols] + value_rows