SQLAlchemy:需要帮助将这个复杂的原始查询转换为ORM(子查询,窗口函数)

时间:2017-11-24 21:36:29

标签: python postgresql sqlalchemy

这是一个postgres查询,我想将其翻译成sqlalchemy ORM:

SELECT
  *
FROM
  (
    SELECT
      *, 
      date_trunc(
        'hour',
        time_obs + INTERVAL '15' MINUTE
      ) AS usedTimestamp,
      ROW_NUMBER() OVER(
        PARTITION BY icao,
        date_trunc(
          'hour',
          time_obs + INTERVAL '15' MINUTE
        )
      ORDER BY
        LEAST(
          EXTRACT(
            MINUTE
            FROM
              time_obs
          ),
          60 - EXTRACT(
            MINUTE
            FROM
              time_obs
          )
        )
      ) AS seqnum
    FROM
      metar_current
    WHERE
      icao = 'DGAA'
  ) AS dt
WHERE
  seqnum = 1
AND LEAST(
  ` EXTRACT(
    MINUTE
    FROM
      time_obs
  ),
  60 - EXTRACT(
    MINUTE
    FROM
      time_obs
  )
) <= 15
ORDER BY
  time_obs ASC

如果不可能(或者很难)将其转换为sqlalchemy ORM,那么有什么方法可以将其作为原始sql查询,但是使用列名引用结果数据?

1 个答案:

答案 0 :(得分:0)

我花了一段时间,但我能够自己解决这个问题 - 虽然我不确定这是解决问题的最佳方式。

seqnum = func.row_number().over(
    partition_by=[Metar.icao,
                  func.date_trunc('hour', Metar.time_obs + text("INTERVAL '15' MINUTE"))
                  ],
    order_by=func.least(func.extract("MINUTE", Metar.time_obs),
                        60 - func.extract("MINUTE", Metar.time_obs))).label('seqnum')

dt = session.query(Metar,
                   func.date_trunc('hour', Metar.time_obs + text("INTERVAL '15' MINUTE")).label('usedTimestamp'),
                   seqnum
                   ).filter(Metar.icao == icao).subquery('dt')

q = session.query(Metar, dt.c.usedTimestamp).filter(dt.c.seqnum == 1,
                                                    dt.c.icao == Metar.icao,
                                                    dt.c.time_obs == Metar.time_obs,
                                                    func.least(func.extract("MINUTE", Metar.time_obs),
                                                               60 - func.extract("MINUTE", Metar.time_obs)) < 15) \
    .order_by(Metar.time_obs).all()

我加入Metardt而不是像原始原始查询中那样只选择dt的原因是我可以通过Metar访问结果数据的类属性。