由于oracle中的函数功能强大,可以通过first_value函数直接实现,因为它有IGNORE参数,而sql server不支持。这里不再展开。
FIRST_VALUE
{ (expr) [ {RESPECT | IGNORE} NULLS ]
| (expr [ {RESPECT | IGNORE} NULLS ])
}
OVER (analytic_clause)
(1) 数据准备
create table fill_null(
id int primary key identity(1,1) not null,
score int default null)
insert into fill_null values(null);
insert into fill_null values(300);
insert into fill_null values(null);
insert into fill_null values(null);
insert into fill_null values(500);
insert into fill_null values(null);
insert into fill_null values(null);
(2) 用前一个非null值填充null
SELECT *
FROM
(
SELECT f1.id,
f2.score,
ROW_NUMBER() OVER(PARTITION BY f1.id ORDER BY f2.id DESC) AS rownumber
FROM fill_null f1
LEFT JOIN fill_null f2 ON f1.id >= f2.id
AND f2.score IS NOT NULL
) t
WHERE t.rownumber = 1;
(1) 语法:
FIRST_VALUE ( scalar_expression ) OVER ([PARTITION BY
partition_expression, … ] ORDER BY sort_expression [ASC | DESC],
… [rows_range_clause])
(2) 案例:
建立一个高三学生的模拟考试分数表,date字段为模考时间,score为模考分数。下面需要得出一下字段:
fst字段,以该生第一次模考成绩填充。
part_fst字段,以该生不同年份的最后一次模考成绩填充。
bounded_lst字段,以该生第一次成绩到当前成绩为窗口,获取该窗口最后一个记录。
lst字段,以该生最后一次模考成绩填充。
WITH test
as
(
select 1 as id, '20211001' as date,510 as score
UNION ALL
select 2, '20211201',520
UNION ALL
select 3, '20220501',550
UNION ALL
select 4, '20220901',535
UNION ALL
select 5, '20230201',570
UNION ALL
select 6, '20230501',600
)
SELECT id,
date,
score,
FIRST_VALUE(score) OVER(ORDER BY date) AS fst,
FIRST_VALUE(score) OVER(partition by datepart(yy,date) ORDER BY date) AS part_fst,
LAST_VALUE(score) OVER(ORDER BY date) AS bounded_lst,
LAST_VALUE(score) over(ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as lst
FROM test;
(3) 注意:LAST_VALUE和FIRST_VALUE是有区别的;LAST_VALUE是当前窗口的最后一个值,在查询中未指定,默认窗口是从当前分区的第一行到当前行的行。您可以将FIRST_VALUE与deseeding order一起使用,也可以指定一个窗口。
上例中的First_Value(),用法是根据Partition By对数据进行分区,如果忽略Partition By ,那么默认整块数据一个区域,然后根据Order By 进行排序,取出第一个值。
(4) 知识扩展:
分析函数中包含三个分析子句:分组(Partition By), 排序(Order By), 窗口(Window)
窗口就是分析函数分析时要处理的数据范围,就拿SUM来说, 它是SUM窗口中的记录而不是整个分组中的记录(见下面【sum窗口案例】),因此我们在想得到某个栏位的累计值时, 我们需要把窗口指定到该分组中的第一行数据到当前行, 如果你指定该窗口从该分组中的第一行到最后一行,那么该组中的每一个SUM值都会一样,即整个组的总和。窗口子句在这里我只说rows方式的窗口,range方式的这里不提, 此外滑动窗口也不提.。窗口子句中我们经常用到指定第一行,当前行,最后一行这样的三个属性. 第一行是 unbounded preceding, 当前行是 current row, 最后一行是 unbounded following.
出现窗口子句,必须指定Order By子句, 如:
LAST_VALUE(score) over(ORDER BY date ROWS
BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as lst
以上示例指定窗口为整个分组。
当省略窗口子句时:
a) 如果存在Order By则默认的窗口是unbounded preceding and current row
b) 如果同时省略Order By则默认的窗口是unbounded preceding and unbounded following
如果省略分组,则把全部记录当成一个组:
a) 如果存在Order By则默认窗口是unbounded preceding and current row
b) 如果这时省略Order By则窗口默认为unbounded preceding and unbounded following
【sum窗口案例】:
CREATE TABLE B
(modified DATE NOT NULL,
account VARCHAR(10) NOT NULL,
amount INT
);
insert into B values ('20200715', 'SH1', 1000);
insert into B values ('20200717', 'SH1', 2000);
insert into B values ('20200718', 'SH1', 2500);
insert into B values ('20200722', 'SH1', 3000);
select B.modified, B.AMOUNT, sum(amount) OVER(ORDER BY B.MODIFIED) AS AMOUNT_SUM from B;
参考:http://www.itpub.net/thread-703576-3-1.html
https://blog.csdn.net/wanghai__/article/details/5690102?utm_source=blogxgwz3