ORDER BY SQLAlchemy中的子查询

时间:2016-01-21 14:27:26

标签: python sql sqlalchemy subquery

我正在尝试将SQL查询转换为SQLAlchemy查询语言。 为了理解一点查询的意义,我有一个表 security 和一个表评估 security 表描述了我在市场上关注的不同证券(股票):

 id   |           bbg_ticker
------+-------------------------
    1 | 3993 HK Equity
    2 | A2A IM Equity
    3 | AA UN Equity
    4 | AA/ LN Equity
    5 | AAL LN Equity
    6 | AALB NA Equity
    7 | ABBN VX Equity

评估表描述了一个安全一天的值:

security_id |    date    |  px_close   |   volume
------------+------------+-------------+-------------
          1 | 2015-05-18 |       6.754 |     9890000
          1 | 2015-05-19 |       6.802 |    11660773
          1 | 2015-05-20 |       6.802 |    12674694
          1 | 2015-05-21 |       6.735 |     5533000
          1 | 2015-05-22 |        6.85 |    10096288
          2 | 2015-05-18 |      1.0558 |    32198683
          2 | 2015-05-19 |      1.0577 |    17630748
          2 | 2015-05-20 |      1.0606 |    11990913
          2 | 2015-05-21 |      1.0722 |    24492170
          2 | 2015-05-22 |      1.0887 |    28795865
          3 | 2015-05-18 |     13.3587 |     3107029
          3 | 2015-05-19 |     13.0397 |     6276252
          3 | 2015-05-20 |     13.0297 |     3746343
          3 | 2015-05-21 |     12.9599 |     4023997
          3 | 2015-05-22 |     12.9001 |     3438908
          4 | 2015-05-18 |     403.949 |     2059825
          4 | 2015-05-19 |     404.937 |     1153599
          4 | 2015-05-20 |     405.035 |      769304
          4 | 2015-05-21 |     403.455 |      586507
          4 | 2015-05-22 |     399.998 |      878268
          5 | 2015-05-18 |    1049.328 |     4957938

我要做的是在一个确切的日期中选择按音量分类的第10个最佳证券。问题是有时候这个特定日期没有数据(比如周末),所以我想取最后一个音量值(过去最接近的值)。

我在纯SQL中找到了解决方案(以下是2015年5月23日的例子):

SELECT s.bbg_ticker
FROM security s
INNER JOIN valuation v1
    ON v1.security_id = s.id
    AND v1.volume IS NOT NULL
    AND v1.px_close iS NOT NULL
    AND v1.date > '2015-05-16'     # because I don't want too old values..
    AND v1.date <= '2015-05-23'
GROUP BY s.id
ORDER BY (SELECT v.volume
    FROM valuation v
    WHERE v.security_id = s.id
        AND v.volume IS NOT NULL
        AND v.px_close IS NOT NULL
        AND v.date > '2015-05-16'  # same
        AND v.date <= '2015-05-23'
    ORDER BY v.date DESC LIMIT 1
) DESC
LIMIT 10

我想做同样的事情,但使用SQLAlchemy查询语言。由于我的SQL查询中有很多重复,我很确定我可以在不重复的情况下使用SQLAlchemy做更聪明的事情。

我无法使用SQLAlchemy在“ORDER BY”中执行子查询。

有没有人有想法?

谢谢你, 编

编辑:

我的第一个想法是做一些事情:

 Security.query.join(Valuation)\
      .filter(
          Valuation.volume != None,
          Valuation.px_close != None,
          Valuation.date <= date(2015, 05, 23),
          Valuation.date > date(2015, 05, 16)
      ).order_by(
          db.session.query(Valuation.volume).filter(
              Valuation.volume != None,
              Valuation.px_close != None,
              Valuation.date <= date(2015, 05, 23),
              Valuation.date > date(2015, 05, 16)
          ).desc()
      )

但是:

  • 我有一个关于desc()的错误:“AttributeError:'BaseQuery'对象没有属性'desc'”
  • 我在子查询中没有“WHERE v.security_id = s.id”链接,因为我无法访问子查询中的“安全性”

1 个答案:

答案 0 :(得分:1)

我最终找到了解决方案:

Security.query.join(Valuation)\
        .filter(tuple_(Valuation.security_id, Valuation.date).in_(
            db.session.query(Valuation.stock_id, func.max(Valuation.date))\
            .filter(Valuation.volume != None,
                    Valuation.px_close != None,
                    Valuation.date > date(2015, 05, 16),
                    Valuation.date <= date(2015, 05, 23))
            .group_by(Valuation.security_id)))
            .order_by(Valuation.volume.desc())
            .limit(10)
            .all()

产生:

SELECT security.*
FROM security
    JOIN valuation ON security.id = valuation.security_id
    WHERE (valuation.security_id, valuation.date) IN (
        SELECT valuation.security_id, max(valuation.date)
        FROM valuation
        WHERE valuation.volume IS NOT NULL
            AND valuation.px_close IS NOT NULL
            AND valuation.date > "2015-05-16"
            AND valuation.date <= "2015-05-23"
            GROUP BY valuation.security_id
    )
ORDER BY valuation.volume DESC
LIMIT 10

哪个更有效,不需要重复。