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;