Sql 进行分区查询,在当前行(如果有)之前报告分区内的第一个NOTNULL事件

Sql 进行分区查询,在当前行(如果有)之前报告分区内的第一个NOTNULL事件,sql,postgresql,Sql,Postgresql,我有一个登录表,如下所示: person_id | login_at | points_won -----------+----------------+---------------------- 1 | 2017-02-02 | 1 | 2017-02-01 | 2 | 2017-02-01 | 2 1 | 2017-01-29 | 2

我有一个登录表,如下所示:

person_id  |    login_at    |    points_won 
-----------+----------------+----------------------
 1         |   2017-02-02   |    
 1         |   2017-02-01   |    
 2         |   2017-02-01   |    2
 1         |   2017-01-29   |    2
 2         |   2017-01-28   |    
 2         |   2017-01-25   |    1
 3         |   2017-01-22   |    
 3         |   2017-01-21   |    
 1         |   2017-01-10   |    3
 1         |   2017-01-01   |    1
person_id  |    login_at    |    points_won        | last_points_won 
-----------+----------------+----------------------+----------------------
 1         |   2017-02-02   |                      |    2
 1         |   2017-02-01   |                      |    2
 2         |   2017-02-01   |      2               |    2
 1         |   2017-01-29   |      2               |    2
 2         |   2017-01-28   |                      |    1
 2         |   2017-01-25   |      1               |    1
 3         |   2017-01-22   |                      |    
 3         |   2017-01-21   |                      |    
 1         |   2017-01-10   |      3               |    3
 1         |   2017-01-01   |      1               |    1
我想生成一个结果集,其中包含一个points\u won列,其工作方式如下:对于每个基于person\u id的行分区,通过登录在desc对分区进行排序,然后报告分区中排序行的最后一个\u points\u won的第一次出现(如果有)

结果应该是这样的:

person_id  |    login_at    |    points_won 
-----------+----------------+----------------------
 1         |   2017-02-02   |    
 1         |   2017-02-01   |    
 2         |   2017-02-01   |    2
 1         |   2017-01-29   |    2
 2         |   2017-01-28   |    
 2         |   2017-01-25   |    1
 3         |   2017-01-22   |    
 3         |   2017-01-21   |    
 1         |   2017-01-10   |    3
 1         |   2017-01-01   |    1
person_id  |    login_at    |    points_won        | last_points_won 
-----------+----------------+----------------------+----------------------
 1         |   2017-02-02   |                      |    2
 1         |   2017-02-01   |                      |    2
 2         |   2017-02-01   |      2               |    2
 1         |   2017-01-29   |      2               |    2
 2         |   2017-01-28   |                      |    1
 2         |   2017-01-25   |      1               |    1
 3         |   2017-01-22   |                      |    
 3         |   2017-01-21   |                      |    
 1         |   2017-01-10   |      3               |    3
 1         |   2017-01-01   |      1               |    1
或者简单地说:

对于每一行,给我在登录过程中赢得的分数,如果没有,给我分数 我在最近一次登录时获得了分数,他在那里确实获得了一些分数 要点


这也可以在一个窗口内实现,使用。但这在PostgreSQL中还不受支持。一种替代方法是,但仅当窗口函数首先是一个聚合函数时才起作用,该函数对于最后一个_值不是真的,而是具有。要仅使用内置聚合解决此问题,您也可以使用array_agg:

注意:如果创建专用的last_agg聚合,则不需要子查询,如:

CREATE FUNCTION last_val(anyelement, anyelement)
  RETURNS anyelement
  LANGUAGE SQL
  IMMUTABLE
  CALLED ON NULL INPUT
  AS 'SELECT $2';

CREATE AGGREGATE last_agg(anyelement) (
  SFUNC = last_val,
  STYPE = anyelement
);

SELECT tbl.*,
       last_agg(points_won)
         FILTER (WHERE points_won IS NOT NULL)
         OVER (PARTITION BY person_id ORDER BY login_at) last_points_won
FROM   tbl;
编辑:一旦PostgreSQL支持IGNORE NULLS选项,您就可以使用以下查询,该查询也可以在Amazon红移中使用:

SELECT tbl.*,
       last_value(points_won IGNORE NULLS)
         OVER (PARTITION BY person_id ORDER BY login_at ROW BETWEEN UNBOUNCED PRECEDING AND CURRENT ROW) last_points_won
FROM   tbl;

不确定我是否理解您的问题?选择l1.*,从登录l2中选择MaxMake\u confirmation\u at,其中l1.person\u id=l2.person\u id作为登录l1Hmm的最后确认\u at我的示例不好,不能使用MAX我会更正1如果按person\u id订购,示例会更清晰,登录2时,您正在查找最近一次非空事件,该事件不是在当前rowI更新问题之后发生的。我不关心输出的顺序,只关心最后几点中的值是否正确对不起,我只是更新了我的示例,结果不好,我不能使用MAXSee更新的答案。我离开了组别,这样更容易理解,太好了!现在是下一个问题。这在我的9.3安装中运行良好,但在Amazon Redshift中的另一个数据库(本质上是隐藏的postgresql 8)中却不起作用。似乎不支持FILTER子句。还有其他想法吗-@NielsKristian Amazon Redshift基于一个非常古老的PostgreSQL版本,因此对PostgreSQL现在可以实现的功能支持很少。而且,该版本还大量修改了自定义功能和禁用功能。它通常被认为是一个完全不同的数据库。@NielsKristian但好消息是:它似乎支持标准的最后一个_值窗口函数选项;Wohooo,您又对了,但它需要一个框架子句,如:unbounded previous和CURRENT ROW之间的ROW
SELECT tbl.*,
       last_value(points_won IGNORE NULLS)
         OVER (PARTITION BY person_id ORDER BY login_at ROW BETWEEN UNBOUNCED PRECEDING AND CURRENT ROW) last_points_won
FROM   tbl;