Как объединить два запроса в sqlalchemy – raw и orm?

У меня есть следующие запросы:

funds_subq = text('''select distinct on (user_id) user_id, last_value(amount) over(PARTITION BY user_id order BY id asc RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) from transactions order by user_id, ts_spawn desc''') g1 = aliased(Group) u1 = aliased(User) users = Session.query(User.id.label('user_id'), User.name.label('user_name'), User.funds.label('user_funds'), Group.id.label('group_id'), Group.parent_id.label('parent_id'), u1.id.label('owner_id'), u1.name.label('owner_name')). \ select_from(User). \ join(Group, Group.id == User.group_id). \ outerjoin(g1, g1.id == Group.parent_id). \ outerjoin(u1, u1.id == g1.owner_id) 

Итак, как я могу присоединиться к первому ко второму? Я попробовал что-то вроде этого:

 users = users.outerjoin(funds_subq, funds_subq.c.user_ud == User.id) 

Конечно, это не сработало, потому что у money_subq нет атрибута c и он тоже не имеет атрибута subquery() . И эта проблема показывает, что нет возможности использовать мою версию окна запроса.

Как я могу реализовать свой запрос?

Я забыл о вопросе 🙂

Есть мое решение:

  from sqlalchemy.sql.expression import ColumnElement from sqlalchemy.ext.compiler import compiles class Extreme(ColumnElement): def __init__(self, request_column, partition_by, order_by, last=True): super(Extreme, self).__init__() self.request_column = request_column self.partition_by = partition_by self.order_by = order_by self.last = last # @property # def type(self): # return self.func.type def extreme_last(request_column, partition_by, order_by): """ function returns last_value clause like this: last_value(transactions.remains) OVER ( PARTITION BY transaction.user_id order BY transactions.id asc RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) it returns last value of transaction.remains for every user, that means that we can get real balance of every user :param request_column: column, which last value we need :param partition_by: for what entity do we need last_value, eg user_id :param order_by: ordering for get last_value :return: """ return Extreme(request_column, partition_by, order_by) def extreme_first(request_column, partition_by, order_by): """ as same as the `extreme_last` above, but returns first value :param request_column: :param partition_by: :param order_by: :return: """ return Extreme(request_column, partition_by, order_by, last=False) @compiles(Extreme) def compile_keep(extreme, compiler, **kwargs): return "%s(%s) OVER (PARTITION BY %s order BY %s asc RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)" % ( "last_value" if extreme.last else "first_value", compiler.process(extreme.request_column), compiler.process(extreme.partition_by), compiler.process(extreme.order_by) ) 

И есть пример использования. Запрос возвращает поле последней строки каждого пользователя:

 Session.query(distinct(Transaction.user_id).label('user_id'), extreme_last(Transaction.remains, partition_by=Transaction.user_id, order_by=Transaction.id).label('remains'))