postgres/oracle:获取组内最后一个非空值

Mar*_*cha 0 sql oracle postgresql

我有必须“分组”的数据。在每个结果组中,都有具有多个列的行,必须按如下方式处理:对于每个这样的给定列,返回非空的最新值。所以我必须对整个表进行“分组”(gb),并为每一列找到“max-like(NUM)”(下面表示为 NUM)。类似 max 的函数按时间列排序,下面表示为“时间”。换句话说,按 'gb' 分组,按 'time' 排序,最后 desc 为空,获取组中的第一项。

抱歉,这个复杂的描述。我希望一切都清楚。知道如何编写该 sql 查询(oracle/postgres)吗?

例子

CREATE TABLE test (
  gb integer,
  NUM INTEGER,
  time integer
);

--rows=groups, columns=time; so in first row=group data 
--sorted by time are from left to right the middle value 
--in triplet, thus, 2,1,3. Ie. most current non-null value in time is 3.
insert into test VALUES (1,2,1),(1,1,2),(1,3,3);--3
insert into test VALUES (2,1,1),(2,2,2),(2,3,3);--3
insert into test VALUES (3,3,1),(3,2,2),(3,1,3);--1
insert into test VALUES (4,3,1),(4,2,2),(4,null,3);--2
insert into test VALUES (5,2,1),(5,3,2),(5,null,3);--3
insert into test VALUES (6,2,1),(6,null,2),(6,null,3);--2
Run Code Online (Sandbox Code Playgroud)

询问

select
  t.gb,
  '<magic goes here>'
from test t
GROUP BY t.gb ORDER BY t.gb;
Run Code Online (Sandbox Code Playgroud)

预计会返回

1 | 3
2 | 3
3 | 1
4 | 2
5 | 3
6 | 2
Run Code Online (Sandbox Code Playgroud)

wol*_*ats 5

在Oracle中最简单的方法是:

SELECT gb, max(num) keep (DENSE_RANK LAST ORDER BY nvl2(num,time,NULL) NULLS first ) r 
FROM test 
GROUP BY gb
Run Code Online (Sandbox Code Playgroud)

SQL小提琴

还有一种“无组”方法:

SELECT DISTINCT gb, last_value(num ignore nulls)over(PARTITION BY gb ORDER BY time 
       RANGE BETWEEN UNBOUNDED preceding AND UNBOUNDED following) num
FROM test ORDER BY gb 
Run Code Online (Sandbox Code Playgroud)

SQL小提琴


GB  NUM 
--- ----
1   3   
2   3   
3   1   
4   2   
5   3   
6   2   
Run Code Online (Sandbox Code Playgroud)