ノート私の最初の答えは下の編集を参照して、間違っています。
このような何か:
LEAST(GREATEST(SUM(myfield) OVER (window_clause), lower_bound), upper_bound)
SQLAlchemyの表現言語は、ユーザー@pozsがコメントで指摘するように、上記生成されませんほとんど同じ
1 2つの書き込み
import sqlalchemy as sa
import sqlalchemy.ext.declarative as dec
base = dec.declarative_base()
class Foo(base):
__tablename__ = 'foo'
id = sa.Column(sa.Integer, primary_key=True)
points = sa.Column(sa.Integer, nullable=False)
timestamp = sa.Column('tstamp', sa.Integer)
upper_, lower_ = 100, -100
win_expr = func.sum(Foo.points).over(order_by=Foo.timestamp)
bound_expr = sa.func.least(sa.func.greatest(win_expr, lower_), upper_).label('bounded_running_total')
stmt = sa.select([Foo.id, Foo.points, Foo.timestamp, bound_expr])
str(stmt)
# prints output:
# SELECT foo.id, foo.points, foo.tstamp, least(greatest(sum(foo.points) OVER (ORDER BY foo.tstamp), :greatest_1), :least_1) AS bounded_running_total
# FROM foo'
# alternatively using session.query you can also fetch results
from sqlalchemy.orm sessionmaker
DB = sessionmaker()
db = DB()
foos_stmt = dm.query(Foo.id, Foo.points, Foo.timestamp, bound_expr).filter(...)
str(foos_stmt)
# prints output:
# SELECT foo.id, foo.points, foo.tstamp, least(greatest(sum(foo.points) OVER (ORDER BY foo.tstamp), :greatest_1), :least_1) AS bounded_running_total
# FROM foo'
foos = foos_stmt.all()
EDITすることができます意図した結果。
@pozsでは、2つの代替アプローチが提示されています。ここでは、sqlalchemyを介して構築された最初の再帰的クエリ・アプローチを採用しました。
import sqlalchemy as sa
import sqlalchemy.ext.declarative as dec
import sqlalchemy.orm as orm
base = dec.declarative_base()
class Foo(base):
__tablename__ = 'foo'
id = sa.Column(sa.Integer, primary_key=True)
points = sa.Column(sa.Integer, nullable=False)
timestamp = sa.Column('tstamp', sa.Integer)
upper_, lower_ = 100, -100
t = sa.select([
Foo.timestamp,
Foo.points,
Foo.points.label('bounded_running_sum')
]).order_by(Foo.timestamp).limit(1).cte('t', recursive=True)
t_aliased = orm.aliased(t, name='ta')
bounded_sum = t.union_all(
sa.select([
Foo.timestamp,
Foo.points,
sa.func.greatest(sa.func.least(Foo.points + t_aliased.c.bounded_running_sum, upper_), lower_)
]).order_by(Foo.timestamp).limit(1)
)
stmt = sa.select([bounded_sum])
# inspect the query:
from sqlalchemy.dialects import postgresql
print(stmt.compile(dialect=postgresql.dialect(),
compile_kwargs={'literal_binds': True}))
# prints output:
# WITH RECURSIVE t(tstamp, points, bounded_running_sum) AS
# ((SELECT foo.tstamp, foo.points, foo.points AS bounded_running_sum
# FROM foo ORDER BY foo.tstamp
# LIMIT 1) UNION ALL (SELECT foo.tstamp, foo.points, greatest(least(foo.points + ta.bounded_running_sum, 100), -100) AS greatest_1
# FROM foo, t AS ta ORDER BY foo.tstamp
# LIMIT 1))
# SELECT t.tstamp, t.points, t.bounded_running_sum
# FROM t
Iはまた、1つは、これが生成する純粋SQLAlchemyの方法であろう再帰CTEを
で動作する代わりに、セッションを使用することができる方法を強調しており、上記を構築するための基準としてこのlink from the documentationを使用必要な結果。
@pozsが示唆している第2のアプローチは、sqlalchemyを介して使用することもできます。
ソリューションは、このsection from the documentation
これは、あなたが正しい、必要な結果に – pozs
@pozsを生成しません。私は答えを削除するか、歴史的な理由でそれを保持する必要がありますか? –
または修正することができます。あなたがSQLAlchemyでより良く/異なって/それを行う方法を知っているなら、私も興味があります。 – pozs