2015-11-09 37 views
0

我有這些疑問:我如何結合sqlalchemy中的兩個查詢 - 原始和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) 

當然,它並沒有工作,因爲funds_subq沒有c屬性,它不具有subquery()屬性了。 和that問題表明,沒有辦法使用我的版本的窗口查詢。

如何實現我的查詢?

回答

0

我忘記了問題:)

有我的解決方案:

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, e.g. 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) 
    ) 

而且有使用的一個例子。查詢返回每個用戶最後一行的remains字段:

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