简体   繁体   English

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

[英]SQLAlchemy: Counting and ordering by multiple relationships to the same table

I have a class in SQLAlchemy that has multiple relationships to the same secondary table. 我在SQLAlchemy中有一个与同一辅助表具有多个关系的类。 It looks somewhat like this: 它看起来像这样:

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

A job has zero or more tasks. 作业具有零个或多个任务。 A task can have one of four states: "queued", "running", "done" or "failed". 任务可以具有四个状态之一:“已排队”,“正在运行”,“完成”或“失败”。 When querying jobs, I want to see the counts for those tasks split by states, ie how many queued, running, done and failed tasks respectively every job has. 查询作业时,我想查看按状态划分的那些任务的计数,即每个作业分别有多少个排队,运行,完成和失败的任务。 I also want to be able to sort the ouput by any of those counts. 我还希望能够按任何这些计数对输出进行排序。

After a bit of googling, I found out how to do that for one relationship: 经过一番谷歌搜索,我发现了如何为一种关系做这件事:

session.query(Job, func.count(Job.tasks_queued).label("t_queued")).\
outerjoin(Job.tasks_queued).group_by(Job).order_by("t_queued ASC").all()

However, as soon as I try to extend that to more than one relationship, things start to get murky: 但是,一旦我尝试将这种关系扩展到多个关系,事情就开始变得模糊起来:

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

produces this error: 产生此错误:

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

So I somehow need to tell sqlalchemy that the first count refers to the first join and the second to the second join. 因此,我需要以某种方式告诉sqlalchemy,第一个计数是指第一个联接,第二个计数是指第二个联接。 In pure SQL, I would just give the joined tables ad-hoc aliases and then references those aliases instead of the table names in the count() function. 在纯SQL中,我只是给连接的表一个临时别名,然后引用这些别名而不是count()函数中的表名。 How do I do that in SQLAlchemy? 如何在SQLAlchemy中做到这一点?

Same way you can use aliases with sqlalchemy : 使用aliasessqlalchemy方式相同:

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

I think that you need to add distinct to those count s though. 我认为您需要为这些count添加distinct的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM