Python SQLAlchemy:根据同一个表的多个关系进行计数和排序

Python SQLAlchemy:根据同一个表的多个关系进行计数和排序,python,sql,sqlalchemy,Python,Sql,Sqlalchemy,我在SQLAlchemy中有一个类,它与同一个辅助表有多个关系。看起来有点像这样: class Job(Base): __tablename__ = 'jobs' id = Column(Integer, primary_key=True) tasks_queued = relationship("Task", lazy="dynamic", primaryjoin="(Task.state == 'queued') & (Task.job_id

我在SQLAlchemy中有一个类,它与同一个辅助表有多个关系。看起来有点像这样:

class Job(Base):
    __tablename__ = 'jobs'
    id = Column(Integer, primary_key=True)
    tasks_queued = relationship("Task", lazy="dynamic",
        primaryjoin="(Task.state == 'queued') & (Task.job_id == Job.id)")
    tasks_running = relationship("Task", lazy="dynamic",
        primaryjoin="(Task.state == 'running') & (Task.job_id == Job.id)")
    tasks_done = relationship("Task", lazy="dynamic",
        primaryjoin="(Task.state == 'done') & (Task.job_id == Job.id)")
    tasks_failed = relationship("Task", lazy="dynamic",
        primaryjoin="(Task.state == 'failed') & (Task.job_id == Job.id)")

class Task(Base):
    __tablename__ = 'tasks'
    id = Column(Integer, primary_key=True)
    job_id = Column(Integer, ForeignKey("jobs.id"))
    state = Column(String(8), nullable=False, default='queued')
    job = relationship("Job")
作业具有零个或多个任务。任务可以有四种状态之一:“排队”、“运行”、“完成”或“失败”。 查询作业时,我希望看到这些任务按状态划分的计数,即每个作业分别有多少排队、正在运行、已完成和失败的任务。我还希望能够根据这些计数中的任何一个对输出进行排序

在谷歌搜索了一下之后,我发现了如何为一段关系做到这一点:

session.query(Job, func.count(Job.tasks_queued).label("t_queued")).\
outerjoin(Job.tasks_queued).group_by(Job).order_by("t_queued ASC").all()
然而,当我试图将其扩展到一种以上的关系时,事情开始变得模糊起来:

session.query(Job, func.count(Job.tasks_queued).label("t_queued"), 
    func.count(Job.tasks_running).label("t_running")).\
outerjoin(Job.tasks_queued).\
outerjoin(Job.tasks_running).group_by(Job).order_by("t_queued ASC").all()
产生以下错误:

sqlalchemy.exc.OperationalError: (OperationalError) ambiguous column name: tasks.state 'SELECT jobs.id AS jobs_id, count(tasks.state = ? AND tasks.job_id = jobs.id) AS t_queued, count(tasks.state = ? AND tasks.job_id = jobs.id) AS t_running \nFROM jobs LEFT OUTER JOIN tasks ON tasks.state = ? AND tasks.job_id = jobs.id LEFT OUTER JOIN tasks ON tasks.state = ? AND tasks.job_id = jobs.id GROUP BY jobs.id ORDER BY t_queued ASC' ('queued', 'running', 'queued', 'running')

所以我需要告诉sqlalchemy,第一个计数指的是第一个连接,第二个计数指的是第二个连接。在纯SQL中,我只需为连接的表指定特定别名,然后在count()函数中引用这些别名而不是表名。如何在SQLAlchemy中实现这一点?

同样,您可以将
别名
用于
SQLAlchemy

a_q = aliased(Task)
a_r = aliased(Task)
a_d = aliased(Task)
a_f = aliased(Task)
qry2 = (session.query(Job,
                      func.count(a_q.id.distinct()).label("t_queued"),
                      func.count(a_r.id.distinct()).label("t_running"),
                      func.count(a_d.id.distinct()).label("t_done"),
                      func.count(a_f.id.distinct()).label("t_failed"),
                      )
        .outerjoin(a_q, Job.tasks_queued)
        .outerjoin(a_r, Job.tasks_running)
        .outerjoin(a_d, Job.tasks_done)
        .outerjoin(a_f, Job.tasks_failed)
        .group_by(Job)
        .order_by("t_queued ASC")

我认为你需要把
distinct
添加到那些
count
s中。

。但出于好奇:你为什么这样做?问题是,如果执行以下操作:
my\u job.tasks\u done.append(Task())
,它将不会将新的
任务的
状态设置为
done
。因此,这不是一种正常运作的关系。