sql >> データベース >  >> RDS >> Mysql

複雑なSQLクエリをSQLAlchemyに変換します

    あなたのHAVING は正しく処理されますが、間違った式を渡しています。文字列と整数の関係比較のため、Python2を使用しているようです

    '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. MySQLの使用方法に関する包括的なガイド

    2. mysqlクエリからPythonスクリプトを実行する方法は?

    3. OUTパラメータを持つ関数から戻る

    4. MySQLの類似したIDを持つ行の列の乗算の合計