2010-03-15 197 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