Mysql
 sql >> база данни >  >> RDS >> Mysql

Преобразувайте сложна 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 наличието на клауза HAVING превръща заявка в групирана заявка, дори без клауза GROUP BY. Вместо това можете да използвате подзаявка:

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()        



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Определете ранг въз основа на множество колони в MySQL

  2. Няма наличен пакет msyql-server

  3. Как да вмъкна стойности в PHP масив в MySQL таблица?

  4. 15 основни въпроса за интервю за MySQL за администратори на бази данни

  5. Sequelize:Използване на множество бази данни