突然发现dense_rank是个不错的函数,以前一直以为first_value,last_value可以替代 ,但是其实不然.有时候可以用的到大家。
dense_rank
功能描述:根据order by子句中表达式的值,从查询返回的每一行,计算它们与其它行的相对位置。组内的数据按order by子句排序,然后给每一行赋一个号,从而形成一个序列,该序列从1开始,往后累加。每次order by表达式的值发生变化时,该序列也随之增加。有同样值的行得到同样的数字序号(认为null时相等的)。密集的序列返回的时没有间隔的数.
first
功能描述:从dense_rank返回的集合中取出排在最前面的一个值的行(可能多行,因为值可能相等),因此完整的语法需要在开始处加上一个集合函数以从中取出记录
sample:下面例子中dense_rank按部门分区,再按佣金commission_pct排序,first取出佣金最低的对应的所有行,然 后前面的max函数从这个集合中取出薪水最低的值;last取出佣金最高的对应的所有行,然后前面的min函数从这个集合中取出薪水最高的值
last
功能描述:从dense_rank返回的集合中取出排在最后面的一个值的行(可能多行,因为值可能相等),因此完整的语法需要在开始处加上一个集合函数以从中取出记录
sample:下面例子中dense_rank按雇用日期排序,first取出salary最低的对应的所有行,然后前面的max函数从这个集合中取出薪水最低的值;last取出雇用日期最高的对应的所有行,然后前面的min函数从这个集合中取出薪水最高的值
select
department_id,
first_name||' '||last_name employee_name,
hire_date,
salary,
min(salary) keep (dense_rank first order by hire_date) over (partition by department_id) worst,
max(salary) keep (dense_rank last order by hire_date) over (partition by department_id) best
from employees
然后再举个使用dense rank的例子,其实在有些特别的场景,比如我说统计部门最高工资里面入职最早员工的信息,dense rank 的first , last函数就非常好实现.
下面例子是求最大最小值的,其实没有完全利用到我刚才说的那个场景.
create table test( v1 varchar2(20), v2 varchar2(10), v3 varchar2(10)) ;
insert into test (v1, v2, v3) values ('1', '1', 'm');
insert into test (v1, v2, v3) values ('1', '2', 'f');
insert into test (v1, v2, v3) values ('2', '1', 'n');
insert into test (v1, v2, v3) values ('2', '2', 'g');
insert into test (v1, v2, v3) values ('3', '1', 'b');
insert into test (v1, v2, v3) values ('3', '2', 'a');
insert into test (v1, v2, v3) values ('1', '3', 'a');
sql> select t.* ,t.rowid from test t order by v1,v2;
v1 v2 v3 rowid
-------------------- ---------- ---------- ------------------
1 1 m aaasukaaeaaaaisaaa
1 2 f aaasukaaeaaaaisaab
1 3 a aaasukaaeaaaaisaag
2 1 n aaasukaaeaaaaisaac
2 2 g aaasukaaeaaaaisaad
3 1 b aaasukaaeaaaaisaae
3 2 a aaasukaaeaaaaisaaf
怎么实现如下结果:
v1 v3 v3
-------------------- ---------- ----------
1 m a
2 n g
3 b a
------------------------------------------------------------------------------------------------------------
answer:
select v1
,max(v3) keep (dense_rank first order by v2)
,max(v3) keep (dense_rank last order by v2)
from test
group by v1;
-------------------------------------------------------------------------------------------------------------
select department_id, first_name||' '||last_name employee_name, hire_date, salary, min(salary) keep (dense_rank first order by hire_date) over (partition by department_id) worst, max(salary) keep (dense_rank last order by hire_date) over (partition by department_id) bestfrom employees
create table test( v1 varchar2(20), v2 varchar2(10), v3 varchar2(10)) ;insert into test (v1, v2, v3) values ('1', '1', 'm');insert into test (v1, v2, v3) values ('1', '2', 'f');insert into test (v1, v2, v3) values ('2', '1', 'n');insert into test (v1, v2, v3) values ('2', '2', 'g');insert into test (v1, v2, v3) values ('3', '1', 'b');insert into test (v1, v2, v3) values ('3', '2', 'a');insert into test (v1, v2, v3) values ('1', '3', 'a');sql> select t.* ,t.rowid from test t order by v1,v2;
select v1 ,max(v3) keep (dense_rank first order by v2) ,max(v3) keep (dense_rank last order by v2) from testgroup by v1;
