聚合函数表达式放在`FROM`子句

时间:2018-11-09 14:58:42

标签: python orm sqlalchemy

我正在尝试将查询建立到按某些条件过滤并加入另一个模型(Loan)的模型(LoanPayment)中。

第一个模型与第二个模型具有一对多的关系,我想在第二个模型的一列上收集汇总值。

模型的定义如下:

class Loan(Base):
    __tablename__ = 'loan'
    id = Column(Integer, primary_key=True)
    granted_date = Column(Date, nullable=False)
    state = Column(String(50), default='GRANTED', index=True)
    value = Column(Numeric(19, 10, asdecimal=True),
                   nullable=False, default=money.Decimal(0))
    [... other columns ...]

class LoanPayout(Base):
    __tablename__ = 'loan_payout'
    id = Column(Integer, primary_key=True)
    payment_date = Column(Date, nullable=False)
    value = Column(Numeric(19, 10, asdecimal=True),
                   nullable=False, default=money.Decimal(0))
    loan_id = Column(Integer, ForeignKey('loan.id'),
                     nullable=False, index=True)
    loan = relationship('Loan',
                        backref=backref('payouts', lazy='dynamic',),
                        foreign_keys=[loan_id], order_by=payment_date.asc)
    [... other columns ...]

我想查询所有Loan.granted_date记录,并根据特定条件进行过滤(例如state='LATE'),并返回所有相关支出的sum()值,并按贷款。

我尝试了以下orm查询:

session.query(
    Loan.id,
    Loan.granted_date,
    func.sum(LoanPayout.principal).alias('loan_payout_total'),
).filter(
    Loan.state == 'LATE',
).join(
    LoanPayout
).group_by(Loan.id)

但是SQLAlchemy(版本1.2.13)呈现了以下内容,甚至是无效的SQL:

SELECT
    loan.id AS loan_id,
    loan.sale_date AS loan_sale_date,
    loan_payout_total.sum_1 AS loan_payout_total_sum_1
FROM
    sum(loan_payout.principal) AS loan_payout_total,
    loan
JOIN loan_payout
    ON loan.id = loan_payout.loan_id
WHERE
    loan.state = %(state_1)s
GROUP BY
    loan.id

查询几乎是我所期望的:它正确地连接了两个表,正确呈现了sum()列,并按期望的列进行了分组。

但是它应该将sum()列及其别名放在FROM部分而不是SELECT部分中。

FROM
    sum(loan_payout.principal) AS loan_payout_total,
    loan

然后将一个别名列(该别名列来自该怪异的“ selectable”)放入SELECT子句:

    loan_payout_total.sum_1 AS loan_payout_total_sum_1

如何使用ORM支持使SQLAlchemy正确呈现此查询?

1 个答案:

答案 0 :(得分:1)

代替

func.sum(LoanPayout.principal).alias('loan_payout_total')

您想要一个label

func.sum(LoanPayout.principal).label('loan_payout_total')

FunctionElement.alias()产生一个别名FROM项,这就是为什么将其放在FROM子句中的原因。在例如Postgresql中有效。