Sqlalchemy多次插入失败,列名称中包含百分比符号(%)

时间:2015-12-25 17:16:32

标签: python sqlalchemy

我正在尝试使用sqlalchemy(版本1.0.11)在列名称中具有百分比符号的列的表上执行多插入。可以一次插入一行而不会出现问题,但是当执行带有con.execute() OperationalError异常的多插入时,会出现。

下面的代码重现了这个问题。创建两个表,一个在列中具有百分比名称,另一个没有。 1.列表中包含%的%的多插入失败。 2.在表中逐行插入行,列名为%in。 3.表中的多插入没有列名称中的%。

from sqlalchemy import *

USER = 'root'
PASSWORD = ''
HOST = '127.0.0.1'
DBNAME = 'test'

connect_str = "mysql://{USER}:{PASSWORD}@{HOST}/{DBNAME}".format(
    USER = USER,
    PASSWORD = PASSWORD,
    HOST = HOST,
    DBNAME = DBNAME
)

engine = create_engine(connect_str, echo = False)

metadata = MetaData()

table_with_percent = Table('table_with_percent', metadata,
     Column('A%', Integer),
     Column('B%', Integer)
)

table_no_percent = Table('table_no_percent', metadata,
     Column('A', Integer),
     Column('B', Integer)
)

metadata.create_all(engine, checkfirst = True)

#####################################
# Create rows to be inserted

rows = [(1,2), (3,4), (5,6)]
table_with_percent_rows = [dict(zip(table_with_percent.c.keys(), row)) for row in rows]
table_no_percent_rows = [dict(zip(table_no_percent.c.keys(), row)) for row in rows]

#########################
# Try the inserts

con = engine.connect()

# 1. THIS FAILS! Mutli insert on table with percentage symbol in column names.
# OperationalError: (_mysql_exceptions.OperationalError) (1054, "Unknown column 'A%%' in 'field list'") [SQL: u'INSERT INTO table_with_percent (`A%%`, `B%%`) VALUES (%s, %s)'] [parameters: ((1, 2), (3, 4), (5, 6))]
con.execute(table_with_percent.insert(), table_with_percent_rows)

# 2. But the rows can be inserted one by one:
for row in table_with_percent_rows:
    con.execute(table_with_percent.insert(), row)

# 3. This works! Multi insert on table with no percent in columns
con.execute(table_no_percent.insert(), table_no_percent_rows)

con.close()

更新:我在sqlalchemy问题跟踪器上打开了this问题。

1 个答案:

答案 0 :(得分:1)

警告在列/表名称中使用精美字符(除A-Z0-9_之外的任何字符)是您自己拍摄的保证方法之一在脚下。

TL; DR 这似乎是SQLAlchemy中的一个错误。它错误地转义了名称中包含%的列。您可以转到issue tracker并报告错误(如果尚未报告)。

您希望在do_execute() sqlalchemy.engine.default.DefaultDialect方法中添加断点。它是您的查询和参数从SA传递到数据库驱动程序的位置。在您的情况下,SQL看起来像这样:

INSERT INTO table_with_percent (`A%%`, `B%%`) VALUES (%s, %s)

是的,SQLAlchemy在列名中添加了第二个%。这显然使列无效。您最好在问题跟踪器上询问其发生的原因。

由于幸运的巧合,插入一行是有效的。 "%s" % ("value",)语法用于将参数格式化为查询。格式字符串%%是转义%字符的方法,因此在格式化查询后返回正确的格式:

INSERT INTO table_with_percent (`A%`, `B%`) VALUES (1, 2)

如果插入多行,幸运巧合不会发生,因为参数的格式化是不同的。最后您得到以下查询:

INSERT INTO table_with_percent (`A%%`, `B%%`) VALUES (1, 2), (3, 4), (5, 6)

显然失败了。

PS您可以使用以下语法使其正常工作:

con.execute(table_with_percent.insert().values(table_with_percent_rows))