python – 将复杂的SQL查询转换为SQLAlchemy
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了python – 将复杂的SQL查询转换为SQLAlchemy,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4157字,纯文字阅读大概需要6分钟。
内容图文
![python – 将复杂的SQL查询转换为SQLAlchemy](/upload/InfoBanner/zyjiaocheng/891/bdf7125aa97c4fb5ae697553fb81f19a.jpg)
我没有想法.我现在用Google搜索了一天以上,我仍然找不到任何有用的答案.
直到现在我做了什么,我试图使用原始SQL,但没有运气.
locations = db.session.query(Location, select([text('( 6371 * acos( cos( radians("53.6209798282177") ) * cos( radians( lat ) ) * cos( radians( lng ) - radians("13.96948162900808") ) + sin( radians("53.6209798282177") ) * sin( radians( lat ) ) ) )')]).label('distance')).having('distance' < 25).all()
当使用这个原始SQL查询时,我返回零结果,但是当在mysql中运行相同的查询时,它返回正确的结果.
我进一步想到,当将查询打印到终端时,它不能正确处理HAVING()子句.
打印时我的查询如下所示:
SELECT location.id AS location_id, location.created_date AS location_created_date, location.zip AS location_zip, location.user_id AS location_user_id, location.lat AS location_lat, location.lng AS location_lng, location.city AS location_city
FROM location
HAVING false = 1
如何将此SQL查询转换为SQLAlchemy
SELECT *, ( 6371 * acos( cos( radians(53.6209798282177) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(11.96948162900808) ) + sin( radians(53.6209798282177) ) * sin( radians( lat ) ) ) ) AS distance FROM location HAVING distance < 25 ORDER BY distance;
我的表看起来像这样:
+--------------+----------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------------+------+-----+---------+-------+
| id | varchar(50) | NO | PRI | NULL | |
| created_date | datetime | YES | | NULL | |
| zip | varchar(5) | NO | UNI | NULL | |
| user_id | varchar(50) | NO | | NULL | |
| lat | decimal(15,13) | NO | | NULL | |
| lng | decimal(15,13) | NO | | NULL | |
| city | text | NO | | NULL | |
+--------------+----------------+------+-----+---------+-------+
任何帮助表示赞赏.
解决方法:
你的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('( 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')
您可以通过为great-circle distance创建一个函数来提高查询构造的可读性,并且可以通过一些工作在位置上实现hybrid method:
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 clause的存在也会将查询转换为分组查询.您可以使用子查询:
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()
内容总结
以上是互联网集市为您收集整理的python – 将复杂的SQL查询转换为SQLAlchemy全部内容,希望文章能够帮你解决python – 将复杂的SQL查询转换为SQLAlchemy所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。