我正在尝试将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()
)
但是:
答案 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
哪个更有效,不需要重复。