ORDER BY SQLAlchemy 中的子查询
Posted
技术标签:
【中文标题】ORDER BY SQLAlchemy 中的子查询【英文标题】:Subquery in ORDER BY SQLAlchemy 【发布时间】:2016-01-21 14:27:26 【问题描述】:我正在尝试将 SQL 查询转换为 SQLAlchemy 查询语言。 为了稍微理解查询的意义,我有一个表security和一个表valuation。 证券表描述了我在市场上关注的不同证券(股票):
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】:我终于找到了解决办法:
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
哪个效率更高,不需要重复。
【讨论】:
以上是关于ORDER BY SQLAlchemy 中的子查询的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Flask-SQLAlchemy 中执行多个“order_by”?
Flask 学习-97.Flask-SQLAlchemy 排序 order_by()