2014-01-31 27 views
3

我在执行对多个值进行检查的原始SQL时遇到SQLAlchemy问题。SQLAlchemy WHERE IN单个值(原始SQL)

my_sess.execute(
     "SELECT * FROM table WHERE `key`='rating' AND uid IN :uids", 
     params=dict(uids=some_list) 
    ).fetchall() 

这个查询有两种情况,一种可以工作,一种不可以。如果some_list = [1],它会抛出一个SQL错误,我在)附近出现语法错误。但是如果some_list = [1, 2],查询成功执行。

为什么会发生这种情况的任何原因?

回答

5

不,SQL参数只处理标量值。你必须在这里生成SQL;如果您需要原始SQL,请使用:

statement = "SELECT * FROM table WHERE `key`='rating' AND uid IN ({})".format(
    ', '.join([':i{}'.format(i) for i in range(len(some_list))])) 

my_sess.execute(
     statement, 
     params={'i{}'.format(i): v for i, v in enumerate(some_list)}) 
    ).fetchall() 

例如生成足够的参数以保存带有字符串格式的some_list中的所有值,然后生成匹配参数以填充它们。

更妙的是使用一个literal_column() object做所有的发电为您提供:

from sqlalchemy.sql import literal_column 

uid_in = literal_column('uid').in_(some_list) 
statement = "SELECT * FROM able WHERE `key`='rating' AND {}".format(uid_in) 

my_sess.execute(
     statement, 
     params={'uid_{}'.format(i): v for i, v in enumerate(some_list)}) 
    ).fetchall() 

但你或许可以只生成使用`sqlalchemy.sql.expression模块则整个语句,因为这将使支持多个数据库方言更容易。

而且,uid_in对象已经拥有对绑定参数的正确值的引用;而不是像上面的str.format()动作那样将它转换为字符串,SQLAlchemy将具有实际对象和相关参数,并且不再需要生成params字典或者

下面应该工作:

from sqlalchemy.sql import table, literal_column, select 

tbl = table('table') 
key_clause = literal_column('key') == 'rating' 
uid_clause = literal_column('uid').in_(some_list) 
my_sess.execute(select('*', key_clause & uid_clause, [tbl])) 

其中sqlalchemy.sql.select()采用列规范(这里硬编码为*),where子句(由两个分句产生与&生成一个SQL AND条款)和可选择的列表;在这里你的一个sqlalchemy.sql.table()价值。

快速演示:

>>> from sqlalchemy.sql import table, literal_column, select 
>>> some_list = ['foo', 'bar'] 
>>> tbl = table('table') 
>>> key_clause = literal_column('key') == 'rating' 
>>> uid_clause = literal_column('uid').in_(some_list) 
>>> print select('*', key_clause & uid_clause, [tbl]) 
SELECT * 
FROM "table" 
WHERE key = :key_1 AND uid IN (:uid_1, :uid_2) 

但所有这一切产生的实际对象树包含实际值的绑定参数太多,所以my_sess.execute()可以直接访问这些。

+0

尽管我明白你的答案的作用,并且打印'statement'变量产生了一个有效的SQL,我在调用'execute'方法时得到'AttributeError:'list'对象没有属性'keys'。 –

+0

@EduardLuca:啊,我从不使用'session.execute()',它确实只支持命名参数。将更新。 –

+0

@EduardLuca:但是,您真的应该考虑使用SQLAlchemy的核心功能来生成SQL。我敢打赌,它也可以处理“一代人”。 –