Oracle - 对列进行排名和转换
Oracle - Rank and transform on columns
我在这个 cte_orders 中得到了如下示例数据。每行都是一个订单,包含 user_id、zone_code 和 zone_name.
我需要为每个 user_id 排名前 3 zone_code,并且我需要输出在列上。
像这样
|user_id | top1_zone | top2_zone | top3_zone |
|--------+-------------+-------------+-------------+
|1000 | 5555-ABCD | 4567-ZMNY | 7888-IXPO |
|--------+-------------+-------------+-------------+
|9999 | 3456-JJKL | 7688-HBGT | 5555-ABCD |
|--------+-------------+-------------+-------------+
这是 SQL,其中包含我正在尝试的测试数据和查询。
此查询的问题是为排名的每个位置给出了一行结果。
(
SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
)
select
user_id,
CASE WHEN rank_zones = 1 then zone_concat end as top1_zone,
CASE WHEN rank_zones = 2 then zone_concat end as top2_zone,
CASE WHEN rank_zones = 3 then zone_concat end as top3_zone
from
(
select
user_id,
zone_code||'-'||zone_name as zone_concat,
row_number() over (partition by user_id order by count(*) desc) rank_zones
from cte_orders
group by
user_id,
zone_code||'-'||zone_name
)
where rank_zones <= 3
group by
user_id,
CASE WHEN rank_zones = 1 then zone_concat end,
CASE WHEN rank_zones = 2 then zone_concat end,
CASE WHEN rank_zones = 3 then zone_concat end
order by user_id;
我得到的输出
|user_id | top1_zone | top2_zone | top3_zone |
|--------+-------------+-------------+-------------+
|1000 | 5555-ABCD | (null) | (null) |
|--------+-------------+-------------+-------------+
|1000 | (null) | 4567-ZMNY | (null) |
|--------+-------------+-------------+-------------+
|1000 | (null) | (null) | 7888-IXPO |
|--------+-------------+-------------+-------------+
|9999 | 3456-JJKL | (null) | (null) |
|--------+-------------+-------------+-------------+
|9999 | (null) | 7688-HBGT | (null) |
|--------+-------------+-------------+-------------+
|9999 | (null) | (null) | 5555-ABCD |
|--------+-------------+-------------+-------------+
如何修复我的查询,使每个 user_id 没有空值的行?
How can i fix my query to get one row for each user_id without the nulls?
经过一点点汇总(结果是评论)。
示例数据:
SQL> with cte_orders as (
2 SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
3 SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
4 SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
5 SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
6 SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
7 SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
8 SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
9 SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
10 SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
11 SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
12 SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
13 SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
14 SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
15 SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
16 SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
17 SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
18 SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
19 SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
20 SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
21 SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
22 SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
23 SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
24 SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
25 )
这就是您所要求的(MAX
聚合函数;第 28 - 30 行):
26 select
27 user_id,
28 max(CASE WHEN rank_zones = 1 then zone_concat end) as top1_zone,
29 max(CASE WHEN rank_zones = 2 then zone_concat end) as top2_zone,
30 max(CASE WHEN rank_zones = 3 then zone_concat end) as top3_zone
31 from
32 (
33 select
34 user_id,
35 zone_code||'-'||zone_name as zone_concat,
36 row_number() over (partition by user_id order by count(*) desc) rank_zones
37 from cte_orders
38 group by
39 user_id,
40 zone_code||'-'||zone_name
41 )
42 where rank_zones <= 5
评论 CASE
表达式(第 45 - 47 行):
43 group by
44 user_id
45 -- CASE WHEN rank_zones = 1 then zone_concat end,
46 -- CASE WHEN rank_zones = 2 then zone_concat end,
47 -- CASE WHEN rank_zones = 3 then zone_concat end
48 order by user_id;
然后结果是:
USER TOP1_ZONE TOP2_ZONE TOP3_ZONE
---- --------- --------- ---------
1000 5555-ABCD 4567-ZMNY 5599-HZTR
9999 3456-JJKL 5555-ABCD 7688-HBGT
SQL>
您可以使用 oracle pivot 如下:
with cte_orders as(
SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
),
cte as(select
user_id,
zone_code||'-'||zone_name as zone_concat,
row_number() over (partition by user_id order by count(*) desc ) rank_zones
from cte_orders
group by
user_id,
zone_code||'-'||zone_name)
select user_id,"1" top1_zone, "2" top2_zone, "3" top3_zone
from cte
PIVOT (
MAX(ZONE_CONCAT) FOR rank_zones IN (1,2,3)
)
输出:
USER_ID
TOP1_ZONE
TOP2_ZONE
TOP3_ZONE
1000
5555-ABCD
4567-ZMNY
5599-HZTR
9999
3456-JJKL
5555-ABCD
7688-HBGT
db<>fiddle here
或者您可以在分组依据中使用解码聚合:
with cte_orders as(
SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
),
cte as(select
user_id,
zone_code||'-'||zone_name as zone_concat,
row_number() over (partition by user_id order by count(*) desc ) rank_zones
from cte_orders
group by
user_id,
zone_code||'-'||zone_name)
select user_id,
max(decode(rank_zones,1,ZONE_CONCAT)) top1_zone,
max(decode(rank_zones,2,ZONE_CONCAT)) top2_zone,
max(decode(rank_zones,3,ZONE_CONCAT)) top3_zone
from cte
group by user_id
输出:
USER_ID
TOP1_ZONE
TOP2_ZONE
TOP3_ZONE
1000
5555-ABCD
4567-ZMNY
5599-HZTR
9999
3456-JJKL
5555-ABCD
7688-HBGT
db<>fiddle here
我在这个 cte_orders 中得到了如下示例数据。每行都是一个订单,包含 user_id、zone_code 和 zone_name.
我需要为每个 user_id 排名前 3 zone_code,并且我需要输出在列上。 像这样
|user_id | top1_zone | top2_zone | top3_zone |
|--------+-------------+-------------+-------------+
|1000 | 5555-ABCD | 4567-ZMNY | 7888-IXPO |
|--------+-------------+-------------+-------------+
|9999 | 3456-JJKL | 7688-HBGT | 5555-ABCD |
|--------+-------------+-------------+-------------+
这是 SQL,其中包含我正在尝试的测试数据和查询。 此查询的问题是为排名的每个位置给出了一行结果。
(
SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
)
select
user_id,
CASE WHEN rank_zones = 1 then zone_concat end as top1_zone,
CASE WHEN rank_zones = 2 then zone_concat end as top2_zone,
CASE WHEN rank_zones = 3 then zone_concat end as top3_zone
from
(
select
user_id,
zone_code||'-'||zone_name as zone_concat,
row_number() over (partition by user_id order by count(*) desc) rank_zones
from cte_orders
group by
user_id,
zone_code||'-'||zone_name
)
where rank_zones <= 3
group by
user_id,
CASE WHEN rank_zones = 1 then zone_concat end,
CASE WHEN rank_zones = 2 then zone_concat end,
CASE WHEN rank_zones = 3 then zone_concat end
order by user_id;
我得到的输出
|user_id | top1_zone | top2_zone | top3_zone |
|--------+-------------+-------------+-------------+
|1000 | 5555-ABCD | (null) | (null) |
|--------+-------------+-------------+-------------+
|1000 | (null) | 4567-ZMNY | (null) |
|--------+-------------+-------------+-------------+
|1000 | (null) | (null) | 7888-IXPO |
|--------+-------------+-------------+-------------+
|9999 | 3456-JJKL | (null) | (null) |
|--------+-------------+-------------+-------------+
|9999 | (null) | 7688-HBGT | (null) |
|--------+-------------+-------------+-------------+
|9999 | (null) | (null) | 5555-ABCD |
|--------+-------------+-------------+-------------+
如何修复我的查询,使每个 user_id 没有空值的行?
How can i fix my query to get one row for each user_id without the nulls?
经过一点点汇总(结果是评论)。
示例数据:
SQL> with cte_orders as (
2 SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
3 SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
4 SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
5 SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
6 SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
7 SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
8 SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
9 SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
10 SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
11 SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
12 SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
13 SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
14 SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
15 SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
16 SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
17 SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
18 SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
19 SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
20 SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
21 SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
22 SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
23 SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
24 SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
25 )
这就是您所要求的(MAX
聚合函数;第 28 - 30 行):
26 select
27 user_id,
28 max(CASE WHEN rank_zones = 1 then zone_concat end) as top1_zone,
29 max(CASE WHEN rank_zones = 2 then zone_concat end) as top2_zone,
30 max(CASE WHEN rank_zones = 3 then zone_concat end) as top3_zone
31 from
32 (
33 select
34 user_id,
35 zone_code||'-'||zone_name as zone_concat,
36 row_number() over (partition by user_id order by count(*) desc) rank_zones
37 from cte_orders
38 group by
39 user_id,
40 zone_code||'-'||zone_name
41 )
42 where rank_zones <= 5
评论 CASE
表达式(第 45 - 47 行):
43 group by
44 user_id
45 -- CASE WHEN rank_zones = 1 then zone_concat end,
46 -- CASE WHEN rank_zones = 2 then zone_concat end,
47 -- CASE WHEN rank_zones = 3 then zone_concat end
48 order by user_id;
然后结果是:
USER TOP1_ZONE TOP2_ZONE TOP3_ZONE
---- --------- --------- ---------
1000 5555-ABCD 4567-ZMNY 5599-HZTR
9999 3456-JJKL 5555-ABCD 7688-HBGT
SQL>
您可以使用 oracle pivot 如下:
with cte_orders as(
SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
),
cte as(select
user_id,
zone_code||'-'||zone_name as zone_concat,
row_number() over (partition by user_id order by count(*) desc ) rank_zones
from cte_orders
group by
user_id,
zone_code||'-'||zone_name)
select user_id,"1" top1_zone, "2" top2_zone, "3" top3_zone
from cte
PIVOT (
MAX(ZONE_CONCAT) FOR rank_zones IN (1,2,3)
)
输出:
USER_ID | TOP1_ZONE | TOP2_ZONE | TOP3_ZONE |
---|---|---|---|
1000 | 5555-ABCD | 4567-ZMNY | 5599-HZTR |
9999 | 3456-JJKL | 5555-ABCD | 7688-HBGT |
db<>fiddle here
或者您可以在分组依据中使用解码聚合:
with cte_orders as(
SELECT 1 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 2 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 3 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 4 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 5 as order_id, '1000' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 6 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 7 as order_id, '1000' as user_id, '4567' as zone_code, 'ZMNY' as zone_name from dual union all
SELECT 8 as order_id, '1000' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 9 as order_id, '1000' as user_id, '1999' as zone_code, 'LNKJ' as zone_name from dual union all
SELECT 10 as order_id, '1000' as user_id, '5677' as zone_code, 'OPLH' as zone_name from dual union all
SELECT 11 as order_id, '1000' as user_id, '7888' as zone_code, 'IXPO' as zone_name from dual union all
SELECT 12 as order_id, '9999' as user_id, '5599' as zone_code, 'HZTR' as zone_name from dual union all
SELECT 13 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 14 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 15 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 16 as order_id, '9999' as user_id, '5555' as zone_code, 'ABCD' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 17 as order_id, '9999' as user_id, '7688' as zone_code, 'HBGT' as zone_name from dual union all
SELECT 18 as order_id, '9999' as user_id, '1566' as zone_code, 'LNOI' as zone_name from dual union all
SELECT 19 as order_id, '9999' as user_id, '3456' as zone_code, 'JJKL' as zone_name from dual union all
SELECT 20 as order_id, '9999' as user_id, '7654' as zone_code, 'NNJJ' as zone_name from dual union all
SELECT 21 as order_id, '9999' as user_id, '4433' as zone_code, 'NHJE' as zone_name from dual union all
SELECT 22 as order_id, '9999' as user_id, '4111' as zone_code, 'ABHJ' as zone_name from dual
),
cte as(select
user_id,
zone_code||'-'||zone_name as zone_concat,
row_number() over (partition by user_id order by count(*) desc ) rank_zones
from cte_orders
group by
user_id,
zone_code||'-'||zone_name)
select user_id,
max(decode(rank_zones,1,ZONE_CONCAT)) top1_zone,
max(decode(rank_zones,2,ZONE_CONCAT)) top2_zone,
max(decode(rank_zones,3,ZONE_CONCAT)) top3_zone
from cte
group by user_id
输出:
USER_ID | TOP1_ZONE | TOP2_ZONE | TOP3_ZONE |
---|---|---|---|
1000 | 5555-ABCD | 4567-ZMNY | 5599-HZTR |
9999 | 3456-JJKL | 5555-ABCD | 7688-HBGT |
db<>fiddle here