wmsys.wm_concat();行转列。多行合并用“,”分割。
select t.user_id,wmsys.wm_concat(r.role_name) over(partition by t.user_id order by r.role_name asc) from t_user_role t,t_role r
where t.role_id = r.role_id
rank()、dense_rank()、row_number()分析函数
Rank,Dense_rank,Row_number函数为每条记录产生一个从1开始至N的自然数,N的值可能小于等于记录的总数。这3个函数的唯一区别在于当碰到相同数据时的排名策略。
①ROW_NUMBER:
Row_number函数返回一个唯一的值,当碰到相同数据时,排名按照记录集中记录的顺序依次递增。
②DENSE_RANK:
Dense_rank函数返回一个唯一的值,除非当碰到相同数据时,此时所有相同数据的排名都是一样的。
③RANK:
Rank函数返回一个唯一的值,除非遇到相同的数据时,此时所有相同数据的排名是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间空出排名。
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
注意:带空值的排名,默认是第一的。
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让空值排名最后后第一。
First/Last排名查询:
想象一下下面的情形:找出订单总额最多、最少的客户。按照前面我们学到的知识,这个至少需要2个查询。第一个查询按照订单总额降序排列以期拿到第一名,第二个查询按照订单总额升序排列以期拿到最后一名。是不是很烦?因为Rank函数只告诉我们排名的结果,却无法自动替我们从中筛选结果。
幸好Oracle为我们在排列函数之外提供了两个额外的函数:first、last函数,专门用来解决这种问题。还是用实例说话:
SQL > select min(customer_id)
2 keep (dense_rank first order by sum (customer_sales) desc ) first,
3 min(customer_id)
4 keep (dense_rank last order by sum(customer_sales) desc) last
5 from user_order
6 group by customer_id;
FIRST LAST
-- -------- ----------
31 1
这里有几个看起来比较疑惑的地方:
①为什么这里要用min函数
②Keep这个东西是干什么的
③fist/last是干什么的
④dense_rank和dense_rank()有什么不同,能换成rank吗?
首先解答一下第一个问题:min函数的作用是用于当存在多个First/Last情况下保证返回唯一的记录。假如我们去掉会有什么样的后果呢?
SQL > select keep (dense_rank first order by sum (customer_sales) desc ) first,
2 keep (dense_rank last order by sum (customer_sales) desc ) last
3 from user_order
4 group by customer_id;
select keep (dense_rank first order by sum (customer_sales) desc ) first,
*
ERROR at line 1 :
ORA - 00907 : missing right parenthesis
接下来看看第2个问题:keep是干什么用的?从上面的结果我们已经知道Oracle对排名的结果只“保留”2条数据,这就是keep的作用。告诉Oracle只保留符合keep条件的记录。
那么什么才是符合条件的记录呢?这就是第3个问题了。dense_rank是告诉Oracle排列的策略,first/last则告诉最终筛选的条件。
第4个问题:如果我们把dense_rank换成rank呢?
SQL > select min (region_id)
2 keep(rank first order by sum (customer_sales) desc ) first,
3 min (region_id)
4 keep(rank last order by sum (customer_sales) desc ) last
5 from user_order
6 group by region_id;
select min (region_id)
*
ERROR at line 1 :
ORA - 02000 : missing DENSE_RANK