2010-03-15 192 views
3

我有这样定义的声明表:SQLAlchemy的自定义查询列

class Transaction(Base): 
    __tablename__ = "transactions" 
    id = Column(Integer, primary_key=True) 
    account_id = Column(Integer) 
    transfer_account_id = Column(Integer) 
    amount = Column(Numeric(12, 2)) 
    ... 

查询应该是:

SELECT id, (CASE WHEN transfer_account_id=1 THEN -amount ELSE amount) AS amount 
FROM transactions 
WHERE account_id = 1 OR transfer_account_id = 1 

我的代码是:

query = Transaction.query.filter_by(account_id=1, transfer_account_id=1) 
query = query.add_column(case(...).label("amount")) 

但它不”请替换amount列。

一直试图做几个小时,我不想使用原始SQL。

回答

1

您所做的任何查询都不会替换原来的amount列。但是你可以用下面的查询加载另一列:

q = session.query(Transaction, 
        case([(Transaction.transfer_account_id==1, -1*Transaction.amount)], else_=Transaction.amount).label('special_amount') 
       ) 
q = q.filter(or_(Transaction.account_id==1, Transaction.transfer_account_id==1)) 

这不会只返回Transaction对象,而是tuple(Transaction, Decimal)


但是如果你想要这个属性是你的目标的一部分,那么:
由于您的case when ...函数完全独立于WHERE中的条件,因此我建议您按以下方式更改代码:

1)添加属性给你的对象,它执行case when ...检查如下:

@property 
def special_amount(self): 
    return -self.amount if self.transfer_account_id == 1 else self.amount 

您可以完全包裹量的这种特殊处理提供setter属性,以及:

@special_amount.setter 
def special_amount(self, value): 
    if self.transfer_account_id is None: 
     raise Exception('Cannot decide on special handling, because transfer_account_id is not set') 
    self.amount = -value if self.transfer_account_id == 1 else value 

2 )解决您的查询只能有一个过滤器子句or_子句(它看起来像你的查询不会在所有的工作):

q = session.query(Transaction).filter(
    or_(Transaction.account_id==1, 
     Transaction.transfer_account_id==1) 
) 

# then get your results with the proper amount sign: 
for t in q.all(): 
    print q.id, q.special_amount 
+0

排序怎么样?我可以抛出一个order_by()吗? – 2010-03-16 15:57:13

+0

与查询 - 当然;使用@property - 在数据库上执行查询时并不是真的,但是当您检索并存储在列表中时,您可以轻松地对Transaction对象进行排序。 – van 2010-03-16 16:27:57

1

您正在寻找的构造称为column_property。您可以使用辅助映射器来实际替换数量列。您是否确定自己不会为了自己而陷入困境?不仅仅是将负值直接存储在数据库中,还是给“更正”列另设一个名称?

from sqlalchemy.orm import mapper, column_property 
wrongmapper = sqlalchemy.orm.mapper(Transaction, Transaction.__table, 
    non_primary = True, 
    properties = {'amount': 
     column_property(case([(Transaction.transfer_account_id==1, -1*Transaction.amount)], 
     else_=Transaction.amount)}) 

Session.query(wrongmapper).filter(...) 
+0

很好,但不完全正确。我不能使用外部参数。 – 2010-03-15 17:19:38