如何计算某个值之前有多少行?

时间:2016-08-24 18:42:04

标签: sql postgresql postgresql-9.5

如果我有下表:

CREATE TABLE test (
       c_id INTEGER,
       ref_date DATE,
       success BOOLEAN
);

INSERT INTO test
VALUES
(8, '2016-01-01', FALSE),
(8, '2016-01-04', TRUE),
(8, '2016-01-07', FALSE),
(8, '2016-01-09', FALSE),
(8, '2016-01-15', TRUE),
(9, '2016-01-05', TRUE)
;

我想构建一个返回以下内容的查询:

8, '2016-01-01', FALSE,
8, '2016-01-04', TRUE, 2
8, '2016-01-07', FALSE,
8, '2016-01-09', FALSE,
8, '2016-01-15', TRUE, 3
9, '2016-01-05', TRUE, 1

我尝试做的是,对于每个c_id,按日期排序,然后对于成功列中的每个TRUE值计算自该c_id或最后一个TRUE值的第一行以来的行数。因此,在示例输出中,第二行有两个,因为当ref_dates被排序时,第一个TRUE值是自该c_id的组开始以来的第二行。第二行到最后一行有一个3,因为它是TRUE,而自上一个TRUE值以来的第三行。

我试图计算获得成功推荐所需的推荐次数。

我原本以为我可以使用lag()窗口函数构建查询,但是没有办法将前一个绑定设置为成功属性的TRUE值的最后一行。

如何计算某个值之前有多少行?

我正在运行PostgreSQL 9.5。

1 个答案:

答案 0 :(得分:3)

我觉得这可以进一步简化,但这个查询可以使用:

  • lag标记作为不同逻辑分组的开头的行
  • 累计sum标记具有唯一分组ID的同一逻辑分组的所有行
  • count按逻辑分组ID
  • 进行分区

查询:

with grp_start_cte as (
  select *,
         coalesce(lag(success) over (partition by c_id order by ref_date), true) as is_grp_start
    from test
), grp_cte as (
  select *,
         sum(case when is_grp_start then 1 else 0 end) over (partition by c_id order by ref_date) as grp_id
    from grp_start_cte
)
select c_id, ref_date, success,
       case when success then count(*) over (partition by c_id, grp_id) end as cnt
  from grp_cte
 order by c_id, ref_date