bnj*_*jmn 4 python postgresql sqlalchemy window-functions
在sqlalchemy(postgresqlDB)中,我想创建一个有界和函数,因为缺少一个更好的术语.目标是在定义的范围内创建运行总计.
目前,我有一些非常适合计算没有边界的运行总计的东西.像这样的东西:
from sqlalchemy.sql import func
foos = (
db.query(
Foo.id,
Foo.points,
Foo.timestamp,
func.sum(Foo.points).over(order_by=Foo.timestamp).label('running_total')
)
.filter(...)
.all()
)
Run Code Online (Sandbox Code Playgroud)
但是,我希望能够将这个运行总数限制在一个特定的范围内,比如说[-100, 100].所以我们会得到这样的东西(见running_total):
{'timestamp': 1, 'points': 75, 'running_total': 75}
{'timestamp': 2, 'points': 50, 'running_total': 100}
{'timestamp': 3, 'points': -100, 'running_total': 0}
{'timestamp': 4, 'points': -50, 'running_total': -50}
{'timestamp': 5, 'points': -75, 'running_total': -100}
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
不幸的是,没有内置聚合可以帮助您通过窗口函数调用实现预期的输出.
您可以通过递归CTE逐个手动计算行来获得预期的输出:
with recursive t as (
(select *, points running_total
from foo
order by timestamp
limit 1)
union all
(select foo.*, least(greatest(t.running_total + foo.points, -100), 100)
from foo, t
where foo.timestamp > t.timestamp
order by foo.timestamp
limit 1)
)
select timestamp,
points,
running_total
from t;
Run Code Online (Sandbox Code Playgroud)
不幸的是,使用SQLAlchemy很难实现这一点.
您的另一个选择是,根据您的特定需求编写自定义聚合,例如:
create function bounded_add(int_state anyelement, next_value anyelement, next_min anyelement, next_max anyelement)
returns anyelement
immutable
language sql
as $func$
select least(greatest(int_state + next_value, next_min), next_max);
$func$;
create aggregate bounded_sum(next_value anyelement, next_min anyelement, next_max anyelement)
(
sfunc = bounded_add,
stype = anyelement,
initcond = '0'
);
Run Code Online (Sandbox Code Playgroud)
有了这个,您只需要将呼叫替换sum为以下呼叫bounded_sum:
select timestamp,
points,
bounded_sum(points, -100.0, 100.0) over (order by timestamp) running_total
from foo;
Run Code Online (Sandbox Code Playgroud)
后一种解决方案也可能更好地扩展.
http://rextester.com/LKCUK93113
| 归档时间: |
|
| 查看次数: |
681 次 |
| 最近记录: |