Подзапрос SQLAlchemy для суммирования значений из другой таблицы - PullRequest
3 голосов
/ 17 октября 2011

Я изо всех сил пытаюсь понять правильный синтаксис для выполнения подзапроса в SQLAlchemy, когда необходимо вернуть значение (т. Е. Не используется в WHERE).

Я использую декларативный подход.

Используются две модели:

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)

Смысл запроса - определить текущую сумму, выставленную для каждого проекта, используя подзапрос для суммирования связанных счетов. Есть и другие причины, по которым это делается в подзапросе, а не просто в соединении, поэтому мне действительно нужно выяснить проблему подзапроса.

Это пример моего текущего запроса SA:

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()

У меня такое чувство, что это будет стыдно, но я не могу взломать код, чтобы заставить это работать.

Я пробовал почти все образцы, которые я могу найти, со смешанными результатами. Если я опускаю аргумент .correlate (), я получаю следующую ошибку:

'Alias' object has no attribute 'MasterProjectID'

Я также безуспешно пытался добавить следующее выражение в конец подзапроса ():

.correlate(ProjectMasters.MasterProjectID, ProjectInvoices.MasterProjectID)

Если я включу аргумент корреляции, я получу следующую ошибку:

TypeError: Boolean value of this clause is not defined

Заранее спасибо за помощь ...

1 Ответ

5 голосов
/ 17 октября 2011

Обычно я бы использовал column_property для удовлетворения такого требования, например

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,
    )

После этого вы можете использовать его как обычный атрибут, например

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