3

次のように定義された宣言型テーブルがあります。

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を使用したくありません。

4

2 に答える 2

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(...)
于 2010-03-15T02:15:09.420 に答える
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

セッタープロパティを提供する金額のこの特別な処理を完全にラップすることもできます。

@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
于 2010-03-15T17:30:08.103 に答える