在 postgresql 中计算运行的长度

Posted

技术标签:

【中文标题】在 postgresql 中计算运行的长度【英文标题】:Calculating the length of a run in postgresql 【发布时间】:2018-06-07 14:49:03 【问题描述】:

我有一个来自日志记录应用程序的数据集。它记录时间以及我的小部件是否正常:

CREATE TABLE runs (time int, ok int);

INSERT INTO runs VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 1),
(5, NULL),
(6, NULL),
(7, 1),
(8, 1),
(9, NULL),
(10, 1)

我想使用窗口函数(我认为)来确定这些“ok”-ness 运行的长度。所以最终的数据集应该是这样的:

time | ok_length
----------------
 2   |   3
 7   |   2
 10  |   1

据我所知:

SELECT
  time,
  ok,
  CASE WHEN
    LAG(ok) OVER (ORDER BY time) IS NOT null
    THEN SUM(ok) OVER (ORDER BY time) END
FROM runs
ORDER BY time

但它完全错误。任何人都可以帮忙吗?也许我必须对窗口函数末尾的框架做一些事情,但是该框架必须有条件在它达到 NULL 时停止。 这是我正在使用的 SQL 小提琴:http://sqlfiddle.com/#!17/98bf4/3

【问题讨论】:

【参考方案1】:

我认为有一些方法可以简化这一点,但这些基于值查询的计数类型总是有点冗长。主要部分有:

group_start_cte - 延迟标记作为不同逻辑分组开始的行。 group_cte - 为所有行提供组 ID 的累积总和。 group_cnt - 按逻辑分组 ID 计算分区。 first_time_for_group - 获取小组开始的时间。

最后我们将group_cntfirst_time_for_group 放在一起:

WITH
group_start_cte AS (
SELECT
    TIME,
    ok,
    CASE
      WHEN LAG(ok) OVER (ORDER BY TIME asc) is distinct from ok
      THEN TRUE
    END AS group_start
FROM
    runs
),
group_cte AS (
SELECT
    TIME,
    ok,
    group_start,
    SUM(CASE WHEN group_start THEN 1 ELSE 0 END) OVER (ORDER BY TIME asc) AS grp_id
FROM
    group_start_cte
),
first_time_for_group as (
SELECT
    time,
    grp_id
FROM
    group_cte
WHERE
    group_start IS TRUE
),
group_cnt AS (
SELECT
    grp_id,
    count(*) AS ok_length
FROM
    group_cte
WHERE
    ok IS NOT NULL
GROUP BY
    grp_id
)
SELECT
    TIME,
    ok_length
FROM
    group_cnt
    LEFT JOIN first_time_for_group
    USING (grp_id)
ORDER BY
    time ASC
;

【讨论】:

【参考方案2】:

这里有一些不那么冗长的解决方案:

select distinct
        min(time) over (partition by gp)
        , sum(ok) over (partition by gp)
from (
        select *
                , time - row_number() over (partition by ok order by time asc) gp
        from runs
        where ok is not null
) rs
order by 1

【讨论】:

以上是关于在 postgresql 中计算运行的长度的主要内容,如果未能解决你的问题,请参考以下文章

postgresql——字符串函数

在 PostgreSQL 中计算累积和

Postgresql - 将 varchar 列的大小更改为较低的长度

计算Postgresql中两列之间的运行差异

最快的 PostgreSQL 字段长度查询?

有没有办法使用计数而不是长度来计算排序的查询集?