Sqlalchemy按计算列排序

8
我正在尝试使用sqlalchemy构建一个select查询,但我需要按计算值对结果进行排序,我不确定如何做到这一点。
基本上,我有一个“start_time”和“end_time”列,我想根据start_time然后end_time对结果进行排序,但如果end_time < start_time,我想添加86400000。
end_time + (86400000 if end_time < start_time else 0)

我搞不清楚怎么做。有没有简单的方法在我的表类中添加一个计算属性,并使查询检索该属性?

我尝试使用@property来创建该计算end_time的getter但失败了。

2个回答

13

首先需要定义一个包含SQL函数实现的公式的列。

然后使用定义的列构建查询:

col = tclass.end_time + case([(tclass.end_time<tclass.start_time, 86400000)], else_=0 )
q = session.query(col).order_by(col)
print q

还有一种方法可以将这样的计算列添加到映射对象类定义中:

class TName(Base):
    end_time = Column(Integer)
    start_time = Column(Integer)
    calc_column = end_time + case([(end_time<start_time, 86400000)], else_=0 )

q2 = session.query(TName.calc_column).order_by(TName.calc_column)

这个确实可以工作,但是有没有一种方法可以将一个计算属性添加到我的表中,以便查询总是能够检索到它?请注意,此属性不应存储在数据库中。 - Ofir
这也可以使用SQLAlchemy实现 - 请参见我的答案更新。 - vvladymyrov
如此简单优雅!惊人!10倍。 - Ofir
如果计算值取决于某些变量(而不仅仅是其他列上的计算),该怎么办? - cglacet
我在这里提出了关于同一问题变体的问题。 - cglacet

3
SQLAlchemy文档现在建议使用混合对象来实现这个功能。
例子:
from sqlalchemy.ext.hybrid import hybrid_property

class Tname(Base):
    end_time = Column(Integer)
    start_time = Column(Integer)

    @hybrid_property
    def calc_column(self):
        if self.end_time < self.start_time:
            return self.end_time + 86400000 
        else: 
            return self.end_time

那么,您只需运行典型的查询并按calc_column排序即可。

计算将在数据库内部完成还是在Python应用程序代码中完成?如果在Python中,那可能涉及到通过网络传输大量数据来避免在DB内部进行计算(例如,在WHERE子句中使用calc_column)。 - btubbs
如果您为属性指定表达式,则将在数据库端计算该值,在Python中则不会。 - zgoda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接