【问题标题】:Window functions: PARTITION BY one column after ORDER BY another窗口函数:在 ORDER BY 之后的一列 PARTITION BY
【发布时间】:2019-02-18 13:00:17
【问题描述】:

免责声明:显示的问题比我最初预期的要普遍得多。下面的示例取自另一个问题的解决方案。但现在我正在使用这个示例来解决更多问题 - 主要与时间序列相关(查看右侧栏中的“链接”部分)。

所以我首先尝试更一般地解释这个问题:


我使用的是 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 排序,不再按时间戳排序。这会产生您意想不到的结果。

更笼统地说:问题是即使有序列不是创建的分区的一部分,也要确保特殊排序


示例:

db<>fiddle

我有下表:

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


编辑:我在下面添加了一个自己的解决方案,但我对此感到非常不舒服。好像太复杂了。 我想知道是否有更好的方法来实现这个结果。

【问题讨论】:

  • 没关系,我老了。

标签: sql postgresql window-functions


【解决方案1】:

我自己想出了这个解决方案(希望别人能得到更好的解决方案):

demo:db<>fiddle

  1. 通过ts订购
  2. 使用 lag 窗口函数 (https://www.postgresql.org/docs/current/static/tutorial-window.html) 给出下一个 val
  3. 检查下一个值和当前值是否相同。然后我可以打印出01
  4. 将这些值与有序的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

【讨论】:

    猜你喜欢
    • 2014-10-23
    • 2013-10-11
    • 1970-01-01
    • 2017-12-22
    • 2019-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多