我目前有 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/