我在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中,我只是给连接表ad-hoc别名,然后引用那些别名而不是count()函数中的表名。我如何在SQLAlchemy中执行此操作?
答案 0 :(得分:1)
您可以将aliases
与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
。