Sqlalchemy complex in_ clause with tuple in list of tuples

后端 未结 3 605
梦如初夏
梦如初夏 2020-12-08 17:43

I\'m trying to find a way to cause SQLAlchemy to generate a query of the following form:

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

Is this poss

相关标签:
3条回答
  • 2020-12-08 18:15

    Use tuple_:

    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 讨论(0)
  • 2020-12-08 18:24

    see the tuple_ construct in SQLAlchemy 0.6

    0 讨论(0)
  • 2020-12-08 18:36

    Well, thanks to Hao Lian above, I came up with a functional if painful solution.

    Assume that we have a declarative-style mapped class, Clazz, and a list of tuples of compound primary key values, values (Edited to use a better (IMO) sql generation style):

    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)
    

    This solution works for compound or simple primary keys. It's probably marginally slower than the col.in_(keys) for simple primary keys though.

    I'm still interested in suggestions of better ways to do this, but this way is working for now and performs noticeably better than the or_(and_(conditions)) way, or the for key in keys: do_stuff(q.get(key)) way.

    0 讨论(0)
提交回复
热议问题