繁体   English   中英

SQLAlchemy自定义查询列

[英]SQLAlchemy custom query column

我有一个如下定义的声明表:

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。

您正在寻找的构造称为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(...)

您执行的任何查询都不会替换原始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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM