如何构造一个首先在两列之间执行算术运算并将其作为新列返回的 SQLAlchemy 查询?

How to construct an SQLAlchemy query that first performs an arithmetic operation between two columns and returning it as a new column?

我正在使用 Flask-SQLAlchemy,我有以下简化模型,我用它来跟踪我一整天完成的任务。我想要实现的是计算按任务 ID 和客户端 ID 分组的每个记录任务花费的总时间。

S = TypeVar("S", bound="Tracker")

class Tracker(db.Model):

id = db.Column(Integer)
datetime_start = db.Column(DateTime)
datetime_end = db.Column(DateTime)
task_id = db.Column(Integer, ForeignKey)
client_id = db.Column(Integer, ForeignKey)

我的原始 SQL 查询会给我我想要的结果是这样的:

SELECT client_id , task_id, sum(difference)
FROM (
    SELECT id, 
        datetime_start, 
        datetime_end, 
        client_id, 
        task_id , 
        datetime_end-datetime_start as difference
    FROM trackers
    WHERE client_id NOTNULL
) AS s
GROUP BY task_id , client_id 
ORDER BY client_id 
Raw Data
"id","datetime_start","datetime_end","client_id","task_id"
1,2022-02-21 12:00:00.00000+0800,2022-02-21 12:30:00.00000+0800,347,3
2,2022-02-21 12:30:00.00000+0800,2022-02-21 12:50:00.00000+0800,271,4
3,2022-02-21 13:00:00.00000+0800,2022-02-21 13:20:00.00000+0800,34,1
4,2022-02-21 13:20:00.00000+0800,2022-02-21 13:30:00.00000+0800,347,1
7,2022-02-21 14:50:00.00000+0800,2022-02-21 15:40:00.00000+0800,271,4
8,2022-02-21 15:45:00.00000+0800,2022-02-21 16:45:00.00000+0800,271,6
9,2022-02-21 18:00:00.00000+0800,2022-02-21 19:30:00.00000+0800,29,3
Post-Calculation Data
"client_id","task_id","sum"
29,3,"01:30:00"
34,1,"00:20:00"
271,4,"01:10:00"
271,6,"01:00:00"
347,3,"00:30:00"
347,1,"00:10:00"

我当前的class方法查询代码如下:(灵感来自: & )但是它不起作用(Errors out with BaseQuery is not callable - This leads me down another rabbit洞),我怀疑这是因为我使用的是基于模型的查询,但 link 中显示的示例是基于声明的。)

@classmethod
def custom_report(cls: Type[S], filters: Union[list, BooleanClauseList]):
        return cls.query((cls.datetime_end - cls.datetime_start).label("difference"))
            .filter(*filters)
            .group_by(cls.task_id, cls.client_id)
            .order_by(cls.client_id)

我知道我的 custom_report 查询不完整,因为它仍然没有解决聚合 SUM 函数,但在我到达那里之前,我已经停滞不前了。但是,我确实计划使用此处指出的 subquery() 来完成剩余部分:

更新 1:根据@snakecharmerb 和@CAMILO JOSÉ CRUZ RIVERA 的回复,以下是修改后的有效查询:

@classmethod
def custom_report(cls: Type[S], filters: Union[list, BooleanClauseList]):
    return (
        db.session.query(
            cls.task_id,
            cls.client_id,
            func.sum((cls.datetime_end - cls.datetime_start).label("difference")),
        )
        .filter(*filters)
        .group_by(cls.task_id, cls.client_id)
        .order_by(cls.client_id)
    )

您正在尝试从您未查询的列中进行分组。

尝试在查询中包含这些字段

@classmethod
def custom_report(cls: Type[S], filters: Union[list, BooleanClauseList]):
        return cls.query(cls.task_id, cls.client_id, (cls.datetime_end - cls.datetime_start).label("difference"))
            .filters(*filters)
            .group_by(cls.task_id, cls.client_id)
            .order_by(cls.client_id)