免责声明:所示问题比我最初预期的要普遍得多。下面的示例来自一个解决方案,另一个问题。但是,现在我拿这个样本来解决更多问题-主要与时间序列有关(请看一下右侧栏中的“链接”部分)。
所以我想首先更一般地解释这个问题:
我正在使用PostgreSQL,但我肯定在支持DBMS的其他窗口函数(MS SQL Server,Oracle等)中也存在此问题。
Window functions可用于通过公用属性或值将某些值组合在一起。例如,您可以按日期对行进行分组。然后,您可以计算每个日期内的最大值,平均值或计数行数之类的值。
这可以通过定义PARTITION
来实现。按日期分组将与PARTITION BY date_column
一起使用。现在,您想执行一个需要在组内进行特殊排序的操作(计算行号或汇总一列)。可以通过PARTITON BY date_column ORDER BY an_attribute_column
完成。
现在考虑考虑更好的时间序列分辨率。如果没有日期但是有时间戳怎么办。然后,您将无法再按时间列进行分组。但是,尽管如此,按添加顺序分析数据可能很重要(也许时间戳就是数据集的创建时间)。然后,您意识到一些连续的行具有相同的值,并且您希望通过该公用值对数据进行分组。但是线索是这些行具有不同的时间戳。
这里的问题是您无法执行PARTITION BY value_column
。因为PARTITION BY
首先要强制排序。因此,您的表将在分组之前由value_column
进行排序,并且不再由时间戳进行排序。这样会产生出乎您意料的结果。
更笼统地说:问题是即使已排序的列不属于已创建分区的一部分,也要确保进行特殊排序。
示例:
我有下表:
ts val
100000 50
130100 30050
160100 60050
190200 100
220200 30100
250200 30100
300000 300
500000 100
550000 1000
600000 1000
650000 2000
700000 2000
720000 2000
750000 300
我有一个问题,我必须对列val
的所有绑定值进行分组。但是我想在ts
之前保留订单。为此,我想为每个val
组添加一个具有唯一ID的列
预期结果:
ts val group
100000 50 1
130100 30050 2
160100 60050 3
190200 100 4
220200 30100 5 \ same group
250200 30100 5 /
300000 300 6
500000 100 7
550000 1000 8 \ same group
600000 1000 8 /
650000 2000 9 \
700000 2000 9 | same group
720000 2000 9 /
750000 300 10
首次尝试是使用rank
窗口函数,该函数通常可以完成此工作:
SELECT
*,
rank() OVER (PARTITION BY val ORDER BY ts)
FROM
test
但是在这种情况下,这是行不通的,因为PARTITION BY
子句首先通过分区列(在这种情况下为val
)然后通过其ORDER BY
列对表进行排序。因此,顺序为val, ts
,而不是期望的顺序ts
。因此结果当然不是预期的。
ts val rank
100000 50 1
190200 100 1
500000 100 2
300000 300 1
750000 300 2
550000 1000 1
600000 1000 2
650000 2000 1
700000 2000 2
720000 2000 3
130100 30050 1
220200 30100 1
250200 30100 2
160100 60050 1
问题是:如何通过ts
获取有关订单的组ID?
编辑:我在下面添加了自己的解决方案,但对此感到非常不舒服。似乎太复杂了。 我想知道是否有更好的方法来达到这个结果。
答案 0 :(得分:0)
我自己提出了这个解决方案(希望别人会得到更好的解决方案):
ts
排序val
窗口函数(https://www.postgresql.org/docs/current/static/tutorial-window.html)给出下一个lag
值0
或1
SUM
汇总这些值。这将生成我要寻找的组。他们将val
列进行分组,但通过ts
列确保排序。 查询:
SELECT
*,
SUM(is_diff) OVER (ORDER BY ts)
FROM (
SELECT
*,
CASE WHEN val = lag(val) over (order by ts) THEN 0 ELSE 1 END as is_diff
FROM test
)s
结果:
ts val is_diff sum
100000 50 1 1
130100 30050 1 2
160100 60050 1 3
190200 100 1 4
220200 30100 1 5 \ group
250200 30100 0 5 /
300000 300 1 6
500000 100 1 7
550000 1000 1 8 \ group
600000 1000 0 8 /
650000 2000 1 9 \
700000 2000 0 9 | group
720000 2000 0 9 /
750000 300 1 10