2

I am struggling to understand the proper syntax for executing a subquery in SQLAlchemy when the value needs to be returned (i.e. not used in the WHERE).

I am using the declarative approach.

There are two models being used:

class ProjectInvoices(Base):
    InvoiceID = Column(Integer(unsigned=True), default=0, primary_key=True, autoincrement=True)
    MasterProjectID = Column(Integer(unsigned=True), index=True, nullable=False)
    ExpenseAmount = Column(Numeric(10, 2), default=0)
    HoursAmount = Column(Numeric(10, 2), default=0)
    IsVoid = Column(Boolean, default=0, index=True)
    IsSubmit = Column(Boolean, default=0, index=True)

class ProjectMasters(Base):
    MasterProjectID = Column(Integer(unsigned=True), default=0, primary_key=True, autoincrement=True)
    MasterProjectName = Column(Unicode(255))
    MasterProjectMemo = Column(UnicodeText)
    IsActive = Column(Boolean, default=0, index=True)

The point of the query is to determine the current amount invoiced for each project by using a subquery to sum the related invoices. There are other reasons this is being done in a subquery rather than just a join so I really need to figure out the subquery issue.

This is an example of my current SA query:

sqry = session.query(
  func.sum(
    func.ifnull(ProjectInvoices.ExpenseAmount, 0) 
    + func.ifnull(ProjectInvoices.HoursAmount, 0))).label('billed_total')
).filter(and_(ProjectInvoices.IsVoid == 0, ProjectInvoices.IsSubmit == 1)
).subquery()

result = session.query(
  ProjectMasters.MasterProjectID, 
  ProjectMasters.MasterProjectName, 
  sqry.columns.billed_total.label('invoice_total')
).filter(ProjectMasters.IsActive == 1).all()

I have a feeling this is going to be embarrassing simple but I can't seem to crack the code on getting this to work.

I have tried just about every sample I can find with mixed results. If I leave out the .correlate() argument I receive the following error:

'Alias' object has no attribute 'MasterProjectID'

I have also tried adding the following statement to the end of the subquery() without any luck:

.correlate(ProjectMasters.MasterProjectID, ProjectInvoices.MasterProjectID)

If I do include the correlate argument then I receive the following error:

TypeError: Boolean value of this clause is not defined

Thanks for the help in advance...

1 Answer 1

6

Usually I would use a column_property to handle such requirement, e.g.

class ProjectMasters(Base):
    ...

    billed_total = column_property(
        select(
            [func.sum(
                func.coalesce(ProjectInvoices.ExpenseAmount, 0)
                + func.coalesce(ProjectInvoices.HoursAmount, 0)
            )],
            and_(
                MasterProjectID == ProjectInvoices.MasterProjectID,
                ProjectInvoices.IsVoid == False,
                ProjectInvoices.IsSubmit == True,
            ),
        ).label('billed_total'),
        deferred=True,
    )

After that, you can use it like an ordinary attribute, e.g.

result = session.query(
    ProjectMasters.MasterProjectID, 
    ProjectMasters.MasterProjectName, 
    ProjectMasters.billed_total.label('invoice_total'),
).filter(ProjectMasters.IsActive == 1).all()
Sign up to request clarification or add additional context in comments.

1 Comment

freaking awesome! I bang my head on the desk and tell myself I should go back to just using SQL then an answer like this makes the choice of SA feel like such a great idea. Thx...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.