您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

将复杂的SQL查询转换为SQLAlchemy

将复杂的SQL查询转换为SQLAlchemy

HAVING的处理方式正确,但是您传递的是错误的表达式。似乎您正在使用Python 2,因为字符串和整数之间的关系比较

'distance' < 25

不会引发异常,而是求值为False。换句话说,您的查询等于

locations = db.session.query(...).having(False).all()

这就解释了为什么您得到零结果的原因:所有行都被HAVING子句明确过滤掉了,如印刷版所示:

...
HAVING false = 1  -- remove all rows

一种解决方案是使用合适的构造,例如column(),来产生表达式:

locations = db.session.query(...).having(column('distance') < 25).all()

您不应将复杂的选择列表项表达式包装在select()表示SELECT语句的中。标签text()为:

text('( 6371 * acos( cos( radians("53.6209798282177") ) * '
     'cos( radians( lat ) ) * cos( radians( lng ) - radians("13.96948162900808") ) + '
     'sin( radians("53.6209798282177") ) * sin( radians( lat ) ) ) ) '
     'AS distance')

或使用模型构建表达式:

(6371 *
 func.acos(func.cos(func.radians(53.6209798282177)) *
           func.cos(func.radians(Location.lat)) *
           func.cos(func.radians(Location.lng) - func.radians(13.96948162900808)) +
           func.sin(func.radians(53.6209798282177)) *
           func.sin(func.radians(Location.lat)))).label('distance')

你可以通过使功能为提高查询建设的可读性大圆距离,并与工作的一点点,你可以实现一个混合方法Location

import math

def gc_distance(lat1, lng1, lat2, lng2, math=math):
    ang = math.acos(math.cos(math.radians(lat1)) *
                    math.cos(math.radians(lat2)) *
                    math.cos(math.radians(lng2) -
                             math.radians(lng1)) +
                    math.sin(math.radians(lat1)) *
                    math.sin(math.radians(lat2)))

    return 6371 * ang

class Location(db.Model):
    ...
    @hybrid_method
    def distance(self, lat, lng):
        return gc_distance(lat, lng, self.lat, self.lng)

    @distance.expression
    def distance(cls, lat, lng):
        return gc_distance(lat, lng, cls.lat, cls.lng, math=func)

locations = db.session.query(
        Location,
        Location.distance(53.6209798282177,
                          13.96948162900808).label('distance')).\
    having(column('distance') < 25).\
    order_by('distance').\
    all()

请注意,使用HAVING消除非组行的方法不是可移植的。例如,在Postgresql中,即使没有GROUP BY子句,HAVING子句的存在也会将查询转换为分组查询。您可以改用子查询

stmt = db.session.query(
        Location,
        Location.distance(53.6209798282177,
                          13.96948162900808).label('distance')).\
    subquery()

location_alias = db.aliased(Location, stmt)

locations = db.session.query(location_alias).\
    filter(stmt.c.distance < 25).\
    order_by(stmt.c.distance).\
    all()
SQLServer 2022/1/1 18:28:55 有536人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶