2009-06-04 72 views
6

我试图找到一种方法,使SQLAlchemy中生成以下形式的SQL:SQLAlchemy的复杂IN_条款

 
select * from t where (a,b) in ((a1,b1),(a2,b2)); 

这可能吗?

如果不是,有什么建议在模拟它的方法上?

谢谢亲切!

回答

3

好吧,多亏了上面的郝连,我想出了一个功能如果痛苦的解决方案。

假设我们有一个声明式映射类,Clazz,和化合物的主键值的元组的listvalues (编辑,以使用更好的(IMO)SQL生成式):

 
from sqlalchemy.sql.expression import text,bindparam 
... 
    def __gParams(self, f, vs, ts, bs): 
     for j,v in enumerate(vs): 
      key = f % (j+97) 
      bs.append(bindparam(key, value=v, type_=ts[j])) 
      yield ':%s' % key 

    def __gRows(self, ts, values, bs): 
     for i,vs in enumerate(values): 
      f = '%%c%d' % i 
      yield '(%s)' % ', '.join(self.__gParams(f, vs, ts, bs)) 

    def __gKeys(self, k, ts): 
     for c in k: 
      ts.append(c.type) 
      yield str(c) 

    def __makeSql(self,Clazz, values): 
     t = [] 
     b = [] 
     return text(
       '(%s) in (%s)' % (
        ', '.join(self.__gKeys(Clazz.__table__.primary_key,t)), 
        ', '.join(self.__gRows(t,values,b))), 
       bindparams=b) 

该解决方案适用于复合主键或简单主键。尽管对于简单的主键,它可能稍微慢于col.in_(keys)

我仍然对更好的方式提出建议感兴趣,但这种方式现在正在运行,并且执行方式明显优于or_(and_(conditions))方式或for key in keys: do_stuff(q.get(key))方式。

4

标准警告:我并不是SQLAlchemy这个庞大而曲折的生态系统的专家。

假设您有一个名为stocks的表和一个名为session的会话。那么查询也只是像

x = "(stocks.person, stocks.number) IN ((100, 100), (200, 200))" 
session.query(stocks).filter(x).all() 

一个好的经验法则是,SQLAlchemy的将接受在它看起来可能会产生它最多的地方,如filter方法原始的SQL。

但是,我不相信有没有办法做到这一点没有原始的SQL。 in_运算符似乎只在Column s上定义,而不是像你在例子中那样的列的元组。 (另外,这只适用于支持它的SQL实现 - 特别是SQLite在我运行的快速示例中似乎不支持这一点。您还必须小心地限定左元组中的列,特别是如果SQLAlchemy友好地处理表格创作。)

+0

我害怕的是 - 用复合主键打交道时,它会是一个非常有用的结构。感谢你的回答! – lostlogic 2009-06-04 02:51:44

2

看到SQLAlchemy的0.6

17

使用tuple_tuple_ construct

keys = [(a1, b1), (a2, b2)] 
session.query(T).filter(tuple_(T.a, T.b).in_(keys)).all() 

http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.tuple_

+0

警告 警告(来自sqlalchemy doc):所有后端都不支持组合IN构造,目前已知可在PostgreSQL和MySQL上使用,但不支持SQLite。当这种表达式被调用时,不支持的后端将引发DBAPIError的子类。 – Bryan 2017-11-17 16:37:44