我想计算Greenplum中一列的滚动中位数,即如下:
| x | rolling_median_x |
| -- + ---------------- |
| 4 | 4 |
| 1 | 2.5 |
| 3 | 3 |
| 2 | 2.5 |
| 1 | 2 |
| 6 | 2.5 |
| 9 | 3 |
x
是一个整数,每行rolling_median_x
显示当前行和前一行的x
的中位数。例如。第三行rolling_median_x = median(4, 1, 3) = 3
。
到目前为止我发现的事情:
median
函数不能用作框架窗函数,即median(x) OVER(RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
percent_rank
或nth_value
事实上,我无法找到关于哪些功能可以用作Greenplum中的框架窗口功能的适当文档......
我正在使用Greenplum 4.3.4.0(基于Postgres 8.2.15),不幸的是,更新不是一个选项。
答案 0 :(得分:1)
一句话 - 来自维基百科的引用:ORDER BY
ORDER BY是对结果集中的行进行排序的唯一方法。没有 在这个子句中,关系数据库系统可以返回任何行 订单。如果需要订购,则必须提供ORDER BY 应用程序发送的SELECT语句。虽然有些数据库 系统允许在子选择或中指定ORDER BY子句 查看定义,存在没有效果。一个观点是一个 逻辑关系表,关系模型要求a table是一组行,暗示没有任何排序顺序。
由于您需要计算当前和前一行的中位数,因此您必须在表格中添加一行,以定义行的顺序,并且可以使用确定哪一行在给定行之前,哪些行在之后
让我们说一些id
列如下:
| id | x | rolling_median_x |
|----|---|------------------|
| 1 | 4 | 4 |
| 2 | 1 | 2.5 |
| 3 | 3 | 3 |
| 4 | 2 | 2.5 |
| 5 | 1 | 2 |
| 6 | 6 | 2.5 |
| 7 | 9 | 3 |
如果您不能使用分析函数,请尝试纯SQL This article显示了使用SQL计算中位数的各种方法 我认为亨德森的中位数最符合我们的需求:
SELECT CASE COUNT(*) % 2
WHEN 0 -- even sized table
THEN (P1.part_wgt + MIN(CASE WHEN P2.part_wgt > P1.part_wgt
THEN P2.part_wgt
ELSE NULL END))/2.0
ELSE P1.part_wgt --odd sized table
END AS median
FROM Parts AS P1, Parts AS P2
GROUP BY P1.part_wgt
HAVING COUNT(CASE WHEN P1.part_wgt >= P2.part_wgt
THEN 1
ELSE NULL END)
= (COUNT(*) + 1) / 2;
只需将每一行的查询作为依赖子查询运行,一般的想法是这样的:
SELECT t.*, (
SELECT .... Henderson's query FROM table x
WHERE x.id <= t.id
......
) As our_median
FROM table t
您可以在this demo
中找到示例实现SELECT t.*, (
SELECT CASE COUNT(*) % 2
WHEN 0 -- even sized table
THEN (P1.x + MIN(CASE WHEN P2.x > P1.x
THEN P2.x
ELSE NULL END))/2.0
ELSE P1.x --odd sized table
END AS median
FROM Table333 AS P1, Table333 AS P2
WHERE p1.id <= t.id AND p2.id <= t.id
GROUP BY P1.x
HAVING COUNT(CASE WHEN P1.x >= P2.x
THEN 1
ELSE NULL END)
= (COUNT(*) + 1) / 2
) as Our_median
FROM Table333 t;
| id | x | rolling_median_x | our_median |
|----|---|------------------|------------|
| 1 | 4 | 4 | 4 |
| 2 | 1 | 2.5 | 2.5 |
| 3 | 3 | 3 | 3 |
| 4 | 2 | 2.5 | 2.5 |
| 5 | 1 | 2 | 2 |
| 6 | 6 | 2.5 | 2.5 |
| 7 | 9 | 3 | 3 |
此查询可能会很慢 - 这是您必须为使用古老版本的PostgreSQL付出的代价
答案 1 :(得分:0)
我正在使用psql 8.2.15并且遗憾的是更新不是一个选项。
哎哟。
如果是滚动平均值,事情会很简单,但由于需要排序,滚动中位数会很慢。避免这种情况的方法是将值插入到堆或btree中,这样可以获得滚动中值而无需对每个新值进行排序。但这需要自定义代码。
我会用plpython来实现这个: