SQLAlchemy中包含count的子查询

时间:2016-09-30 13:37:01

标签: python sql sqlalchemy

鉴于这些SQLAlchemy模型定义:

class Store(db.Model):
    __tablename__ = 'store'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)


class CustomerAccount(db.Model, AccountMixin):
    __tablename__ = 'customer_account'

    id = Column(Integer, primary_key=True)
    plan_id = Column(Integer, ForeignKey('plan.id'), index=True, nullable=False)

    store = relationship('Store', backref='account', uselist=False)
    plan = relationship('Plan', backref='accounts', uselist=False)


class Plan(db.Model):
    __tablename__ = 'plan'

    id = Column(Integer, primary_key=True)
    store_id = Column(Integer, ForeignKey('store.id'), index=True)
    name = Column(String, nullable=False)
    subscription_amount = Column(Numeric, nullable=False)
    num_of_payments = Column(Integer, nullable=False)
    store = relationship('Store', backref='plans')

如何编写查询以按计划获得订阅收入明细? 我想获取给定商店的计划列表,并为每个计划获取该计划的总收入,通过乘以Plan.subscription_amount * Plan.num_of_payments *订阅该计划的客户数量来计算

目前我正在尝试使用此查询和子查询:

store = db.session.query(Store).get(1)

subscriber_counts = db.session.query(func.count(CustomerAccount.id)).as_scalar()

q = db.session.query(CustomerAccount.plan_id, func.sum(subscriber_counts * Plan.subscription_amount * Plan.num_of_payments))\
  .outerjoin(Plan)\
  .group_by(CustomerAccount.plan_id)

问题是子查询没有过滤当前的计划ID。

我也尝试过这种其他方法(没有子查询):

q = db.session.query(CustomerAccount.plan_id, func.count(CustomerAccount.plan_id) * Plan.subscription_amount * Plan.num_of_payments)\
    .outerjoin(Plan)\
    .group_by(CustomerAccount.plan_id, Plan.subscription_amount, Plan.num_of_payments)

虽然结果似乎很好,但我不知道如何取回计划名称或其他计划列,因为我需要将它们添加到组中(并且会更改结果)

理想情况下,如果一个计划没有任何订阅者,我希望它返回的总数为零。

谢谢!

1 个答案:

答案 0 :(得分:4)

感谢AlexGrönholm在#sqlalchemy上我最终得到了这个有效的解决方案:

from sqlalchemy.sql.expression import label
from sqlalchemy.sql.functions import coalesce

from instalment.models import db
from sqlalchemy import func, desc


def projected_total_money_volume_breakdown(store):
    subscriber_counts = db.session.query(
        CustomerAccount.plan_id,
        func.count(CustomerAccount.id).label('count')
    ).group_by(CustomerAccount.plan_id) \
        .subquery()

    total_amount_exp = coalesce(
        subscriber_counts.c.count, 0
    ) * Plan.subscription_amount * Plan.num_of_payments

    return db.session.query(
            Plan, 
            label('total_amount', total_amount_exp)
        ) \
        .outerjoin(subscriber_counts, subscriber_counts.c.plan_id == Plan.id) \
        .filter(Plan.store == store) \
        .order_by(desc('total_amount')) \
        .all()
相关问题