假设我有一个带有宽度和长度列的ROOMS表,以及一个相应的SQLAlchemy模型。是否有一个干净有效的方法来获得所有房间的总面积,即总和(长度x宽度)?通过在客户端循环可以很容易地完成,但如果可以通过服务器上的查询获取它,那肯定会更有效。
修改
我认为通过将问题简化为一个简单,干净的例子我有所帮助,但我现在意识到我只是在脚下射击,因为我的困难显然源于对SQLAlchemy的更基本的缺乏理解以及与ORM合作。
我的模型(flask-sqlalchemy)实际上涉及三个相关的表:持股,商品和价格。商品有很多价格,每个持有量都是特定商品的数量。我把它设置如下:
class Holding(db.Model):
id = db.Column(db.Integer, primary_key=True)
time = db.Column(db.TIMESTAMP, index=True)
quantity = db.Column(db.DECIMAL(10,5))
commodity_id = db.Column(db.Integer, db.ForeignKey('commodity.id'))
commodity = db.relationship('Commodity', back_populates='holdings')
class Commodity(db.Model):
id = db.Column(db.Integer, primary_key=True)
symbol = db.Column(db.String(20))
name = db.Column(db.String(150))
holdings = db.relationship('Holding', back_populates='commodity', lazy='dynamic')
prices = db.relationship('Price', back_populates='commodity', lazy='dynamic', order_by='Price.time.desc()')
class Price(db.Model):
id = db.Column(db.Integer, primary_key=True)
time = db.Column(db.TIMESTAMP, index=True)
amount = db.Column(db.DECIMAL(10,5), index=True)
commodity_id = db.Column(db.Integer, db.ForeignKey('commodity.id'))
commodity = db.relationship('Commodity', back_populates='prices')
我想要Hold.quantity * Holding.commodity的总和。[最近的价格]。
由于Commodity.prices处于降序时间顺序,我可以轻松地计算保持循环检查中的值:
h.commodity.prices.first().amount * h.quantity
...但我无法看到如何从单个查询中获取相关的价格详细信息,因此我不知道如何应用@ leovp的解决方案。
我希望现在正确地描述问题,为错误的开始道歉。
答案 0 :(得分:2)
关于你的问题,更有趣的部分是解决greatest-n-per-group问题。现在,对于MySQL来说,我非常环保,因此可能会有更有效的解决方案:
In [43]: price_alias = db.aliased(Price)
In [44]: latest_price = db.session.query(Price.commodity_id, Price.amount).\
...: outerjoin(price_alias,
...: db.and_(price_alias.commodity_id == Price.commodity_id,
...: price_alias.time > Price.time)).\
...: filter(price_alias.id == None).\
...: subquery()
自我左连接尝试加入时间时间的行,这些行不存在最新价格,因此filter(price_alias.id == None)
。
剩下的就是将Holding
与子查询一起加入:
In [46]: sum_of_products = db.session.query(
...: db.func.sum(Holding.quantity * latest_price.c.amount)).\
...: join(latest_price,
...: latest_price.c.commodity_id == Holding.commodity_id).\
...: scalar()
答案 1 :(得分:1)
假设您的模型名为Room,并且它具有length
和width
等属性:
from sqlalchemy import func
total_area = session.query(func.sum(Room.length * Room.width))
将被翻译成类似的东西:
SELECT sum(rooms.length * rooms.width) AS sum_1
FROM rooms