sql >> Database teknologi >  >> RDS >> Mysql

Konverter en kompleks SQL-forespørgsel til SQLAlchemy

Din HAVING håndteres korrekt, men du giver det det forkerte udtryk. Det ser ud til, at du bruger Python 2, da den relationelle sammenligning mellem en streng og et heltal

'distance' < 25
 

rejser ikke en undtagelse, men evaluerer til False i stedet. Med andre ord er din forespørgsel lig med

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

hvilket forklarer, hvorfor du får nul resultater:alle rækker er eksplicit filtreret ud af HAVING-sætningen, som det ses i den trykte version:

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

En løsning er at bruge en passende konstruktion, såsom column() , for at fremstille udtrykket:

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

Du bør ikke pakke det komplekse valglisteelement-udtryk ind i en select() , som repræsenterer en SELECT-sætning. Mærk enten text() som den er:

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

eller byg udtrykket ved hjælp af modellen:

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

Du kan forbedre læsbarheden af ​​din forespørgselskonstruktion ved at lave en funktion for store cirkelafstanden a> , og med lidt arbejde kunne du implementere en hybridmetodeLocation :

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

Bemærk, at den måde, du bruger HAVING til at fjerne ikke-grupperækker, ikke er bærbar. For eksempel i Postgresql tilstedeværelsen af ​​HAVING-sætning gør en forespørgsel til en grupperet forespørgsel, selv uden en GROUP BY-sætning. Du kan bruge en underforespørgsel i stedet:

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. Addnode resolv.conf Fejl

  2. Hvad er databasetest, og hvordan udføres det?

  3. mysqldump fejl:Fik pakke større end max_allowed_packet'

  4. Deltag i en optællingsforespørgsel på gener_series() og hent Null-værdier som '0'