注意这里有3条记录的订单总额是一样的。假如我们现在需要筛选排名前12位的客户,如果使用rownum会有什么样的后果呢?
SQL
>
select
rownum, t.
*
2
from
(
select
*
3
from
user_order
4
order
by
customer_sales
desc
) t
5
where
rownum
<=
12
6
order
by
customer_sales
desc
; ROWNUM REGION_ID CUSTOMER_ID CUSTOMER_SALES
--
-------- ---------- ----------- --------------
1
9
25
2232703
2
8
17
1944281
3
7
14
1929774
4
5
4
1878275
5
10
26
1808949
6
6
6
1788836
7
8
20
1413722
8
10
27
1322747
9
7
13
1310434
10
7
15
1255591
11
8
18
1253840
12 5 2 1224992
12
rows selected.
很明显假如只是简单地按rownum进行排序的话,我们漏掉了另外两条记录(参考上面的结果)。 二、使用分析函数来为记录排名: 针对上面的情况,Oracle从8i开始就提供了3个分析函数:rand,dense_rank,row_number来解决诸如此类的问题,下面我们来看看这3个分析函数的作用以及彼此之间的区别:Rank,Dense_rank,Row_number函数为每条记录产生一个从1开始至N的自然数,N的值可能小于等于记录的总数。这3个函数的唯一区别在于当碰到相同数据时的排名策略。 ①ROW_NUMBER:
Row_number函数返回一个唯一的值,当碰到相同数据时,排名按照记录集中记录的顺序依次递增。
②DENSE_RANK: Dense_rank函数返回一个唯一的值,除非当碰到相同数据时,此时所有相同数据的排名都是一样的。
③RANK: Rank函数返回一个唯一的值,除非遇到相同的数据时,此时所有相同数据的排名是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间空出排名。 这样的介绍有点难懂,我们还是通过实例来说明吧,下面的例子演示了3个不同函数在遇到相同数据时不同排名策略:
SQL
>
select
region_id, customer_id,
sum
(customer_sales) total,
2
rank()
over
(
order by sum (customer_sales) desc
) rank,
3
dense_rank()
over
(
order by sum (customer_sales) desc
) dense_rank,
4
row_number()
over
(
order by sum (customer_sales) desc
) row_number
5
from
user_order
6
group
by
region_id, customer_id; REGION_ID CUSTOMER_ID TOTAL RANK DENSE_RANK ROW_NUMBER
--
-------- ----------- ---------- ---------- ---------- ----------
8
18
1253840
11
11
11
5
2
1224992
12
12
12
9
23
1224992
12
12
13
9
24
1224992
12
12
14
10
30
1216858
15 13 15
30
rows selected.
请注意上面的绿色高亮部分,这里生动的演示了3种不同的排名策略: ①对于第一条相同的记录,3种函数的排名都是一样的:12 ②当出现第二条相同的记录时,Rank和Dense_rank依然给出同样的排名12;而row_number则顺延递增为13,依次类推至第三条相同的记录 ③当排名进行到下一条不同的记录时,可以看到Rank函数在12和15之间空出了13,14的排名,因为这2个排名实际上已经被第二、三条相同的记录占了。而Dense_rank则顺序递增。row_number函数也是顺序递增 比较上面3种不同的策略,我们在选择的时候就要根据客户的需求来定夺了:①假如客户就只需要指定数目的记录,那么采用row_number是最简单的,但有漏掉的记录的危险 ②假如客户需要所有达到排名水平的记录,那么采用rank或dense_rank是不错的选择。至于选择哪一种则看客户的需要,选择dense_rank或得到最大的记录 三、使用分析函数为记录进行分组排名: 上面的排名是按订单总额来进行排列的,现在跟进一步:假如是为各个地区的订单总额进行排名呢?这意味着又多了一次分组操作:对记录按地区分组然后进行排 名。幸亏Oracle也提供了这样的支持,我们所要做的仅仅是在over函数中order by的前面增加一个分组子句:partition by region_id。
SQL
>
select
region_id, customer_id,
sum
(customer_sales) total,
2
rank()
over
(partition by region_id
order
by
sum
(customer_sales)
desc
) rank,
3
dense_rank()
over
(partition by region_id
order
by
sum
(customer_sales)
desc
) dense_rank,
4
row_number()
over
(partition by region_id
order
by
sum
(customer_sales)
desc
) row_number
5
from
user_order
6
group
by
region_id, customer_id; REGION_ID CUSTOMER_ID TOTAL RANK DENSE_RANK ROW_NUMBER
--
-------- ----------- ---------- ---------- ---------- ----------
5
4
1878275
1
1
1
5
2
1224992
2
2
2
5
5
1169926
3
3
3
6
6
1788836
1
1
1
6
9
1208959
2
2
2
6
10
1196748
3
3
3
30
rows selected.
现在我们看到的排名将是基于各个地区的,而非所有区域的了!Partition by 子句在排列函数中的作用是将一个结果集划分成几个部分,这样排列函数就能够应用于这各个子集。三.分析函数3(top\bottom n、first\last、ntile)
目录 =============================================== 1.带空值的排列 2.Top/Bottom N查询 3.First/Last排名查询 4.按层次查询 一、带空值的排列: 在前面《Oracle开发专题之:分析函数2(Rank、Dense_rank、row_number) 》一文中,我们已经知道了如何为一批记录进行全排列、分组排列。假如被排列的数据中含有空值呢?
SQL
>
select
region_id, customer_id,
2
sum
(customer_sales) cust_sales,
3
sum
(
sum
(customer_sales))
over
(partition
by
region_id) ran_total,
4
rank()
over
(partition
by
region_id
5
order by sum (customer_sales) desc
) rank
6
from
user_order
7
group
by
region_id, customer_id; REGION_ID CUSTOMER_ID CUST_SALES RAN_TOTAL RANK
--
-------- ----------- ---------- ---------- ----------
10
31
6238901
1
10
26
1808949
6238901
2
10
27
1322747
6238901
3
10
30
1216858
6238901
4
10
28
986964
6238901
5
10
29
903383
6238901
6
我们看到这里有一条记录的CUST_TOTAL字段值为NULL,但居然排在第一名了!显然这不符合情理。所以我们重新调整完善一下我们的排名策略,看看下面的语句:
SQL
>
select
region_id, customer_id,
2
sum
(customer_sales) cust_total,
3
sum
(
sum
(customer_sales))
over
(partition
by
region_id) reg_total,
4
rank()
over
(partition
by
region_id
order by sum (customer_sales) desc NULLS LAST
) rank
5
from
user_order
6
group
by
region_id, customer_id; REGION_ID CUSTOMER_ID CUST_TOTAL REG_TOTAL RANK
--
-------- ----------- ---------- ---------- ----------
10
26
1808949
6238901
1
10
27
1322747
6238901
2
10
30
1216858
6238901
3
10
28
986964
6238901
4
10
29
903383
6238901
5
10
31
6238901
6
绿色高亮处,NULLS LAST/FIRST告诉Oracle让空值排名最后后第一。 注意是NULLS,不是NULL。 二、Top/Bottom N查询: 在日常的工作生产中,我们经常碰到这样的查询:找出排名前5位的订单客户、找出排名前10位的销售人员等等。现在这个对我们来说已经是很简单的问题了。下面我们用一个实际的例子来演示: 【1】找出所有订单总额排名前3的大客户:
SQL
>
select
*
SQL
>
from
(
select
region_id, SQL
>
customer_id, SQL
>
sum
(customer_sales) cust_total, SQL
>
rank() over ( order by sum (customer_sales) desc NULLS LAST) rank
SQL
>
from
user_order SQL
>
group
by
region_id, customer_id) SQL
>
where
rank
<=
3
; REGION_ID CUSTOMER_ID CUST_TOTAL RANK
--
-------- ----------- ---------- ----------
9
25
2232703
1
8
17
1944281
2
7
14
1929774
3
SQL
>