Sqlalchemy 复杂的 in_ 子句与元组列表

12 投票
4 回答
7827 浏览
提问于 2025-04-15 12:02

我正在寻找一种方法,让SQLAlchemy生成如下形式的查询:

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

这可能吗?

如果不行,有什么建议可以模拟这个查询吗?

4 个回答

31

使用 tuple_

from sqlalchemy import 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_

3

首先,感谢上面的Hao Lian,我想出了一个可行但有点麻烦的解决方案。

假设我们有一个声明式风格的映射类,叫做Clazz,还有一个包含复合主键值的元组列表,叫做values。(我编辑了一下,使用了我认为更好的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))的方法表现得更好。

撰写回答