python - 查询一对多和多对一的链

标签 python postgresql sqlalchemy flask-sqlalchemy greatest-n-per-group

我目前有 3 个表,大致描述为以下 SQLAlchemy 映射:

class Task(BASE):
    __tablename__ = 'tasks'
    id = Column(Integer, primary_key=True)

    service_id = Column(Integer, ForeignKey('services.id'))
    service = relationship('Service', back_populates="tasks")

    updates = relationship("TaskUpdate")


class TaskUpdate(BASE):
    __tablename__ = 'task_updates'

    id = Column(Integer, primary_key=True)
    external_status = Column(String(32))
    external_updated_at = Column(DateTime(timezone=True))

    task_id = Column(Integer, ForeignKey('tasks.id'))
    task = relationship('Task', back_populates="updates")


class Service(BASE):
    __tablename__ = 'services'

    id = Column(Integer, primary_key=True)

    client_id = Column(Integer, ForeignKey('clients.id'))
    client = relationship('Client', back_populates='services')

所以我有从任务到任务更新的一对多关系和从任务到服务的多对一关系。

我正在尝试创建一个查询以获取其最新任务更新(按时间戳)的外部状态为“新建”或“打开”的所有任务。

这是我得到的:

sub = SESSION.query(
        TaskUpdate.task_id,
        TaskUpdate.external_status.label('last_status'),
        func.max(TaskUpdate.external_updated_at).label('last_update')
        ).group_by(TaskUpdate.task_id
        ).subquery()
tasks = SESSION.query(Task
        ).join(Service
        ).filter(Service.client_id == client_id
        ).join((sub, sub.c.task_id == Task.id)
        ).filter(sub.c.last_status.in_(['New', 'Open']))

当我运行它时,我得到这个错误:

ProgrammingError: (psycopg2.ProgrammingError) column "task_updates.external_status" must appear in the GROUP BY clause or be used in an aggregate function

如果您能提供任何帮助,我将不胜感激。这很重要。

更新 1(这是最终运行的 SQL(据我所知,在 SQLAlchemy 中运行之前我无法测试前端:

SELECT t.* FROM ( 
  SELECT DISTINCT ON (task_id) task_id, external_status 
  FROM task_updates 
  ORDER BY task_id, external_updated_at DESC NULLS LAST) tu 
JOIN tasks t ON t.id = tu.task_id 
JOIN services s ON s.id = t.service_id 
WHERE s.client_id = '" + str(client_id) + "' 
AND tu.external_status IN ('New', 'Open');

这是我的转换尝试,仍然无效:

sub = SESSION.query(TaskUpdate).distinct(TaskUpdate.task_id).order_by(TaskUpdate.task_id.desc().nullslast(), TaskUpdate.external_updated_at.desc().nullslast()).subquery()
tasks = SESSION.query(Task).join(Service).join(sub.c.task_id==Task.id).filter(TaskUpdate.external_status.in_(['New', 'Open']))

更新 2:下面的查询有效,但是当我执行 .count() 时,它返回任务更新的总数,而不是任务,我怀疑需要以不同的方式重做查询,除非有人知道方法处理这个?

最佳答案

正在执行此操作:

SELECT t.*
FROM  (
   SELECT DISTINCT ON (task_id)
          task_id, external_status
   FROM   task_updates
   ORDER  BY task_id, external_updated_at DESC NULLS LAST
   ) tu
JOIN   tasks t ON t.id = tu.task_id
WHERE  tu.external_status IN ('New', 'Open');

首先获取每个任务的最后一行,然后只选择具有正确external_status 的任务。

DISTINCT ON的详细解释:

如果每个任务有很多行,则有更快的查询技术:

关于python - 查询一对多和多对一的链,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43156331/

相关文章:

sql - 两个日期之间的周数

python - 列数会影响sqlalchemy的速度吗?

python - 如何修复 "AttributeError at/api/doc ' AutoSchema' 对象在 Django 中没有属性 'get_link'"错误

python - 在 Django 管理中为子模型添加按钮

c# - Entity Framework Core Postgres ILike 函数

postgresql - 如何为 postgres 中的每个插入行获取 pg_notify 通知?

python - 在 SQL/MySQL/PostgreSQL 表上执行高级数据清理和格式化的最佳语言/技术是什么?

python - 具有平均时间的 Pandas 数据透视表

python - Python 上的 XMPP 响应 Gtalk,但不响应 Hangouts