Предложение Sqlalchemy complex in_ с кортежем в списке кортежей
-
09-09-2019 - |
Вопрос
Я пытаюсь найти способ заставить SQLAlchemy сгенерировать запрос следующего вида:
select * from t where (a,b) in ((a1,b1),(a2,b2));
Возможно ли это?
Если нет, то есть какие-нибудь предложения о том, как этому подражать?
Решение 2
Что ж, благодаря Хао Лиану выше, я придумал функциональное, хотя и болезненное решение.
Предположим, что у нас есть отображенный класс в декларативном стиле, Clazz
, и a list
из кортежей составных значений первичного ключа, values
(Отредактировано для использования лучшего (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))
образом.
Другие советы
Использование 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_
смотрите на конструкция tuple_ в SQLAlchemy 0.6