如下表,我需要进行查询,将“time”(分钟数,整数)的空值替换为与前后值一致的值,并按“esz”分区并按“升序”排序秩”。在示例中,数据已经排序。 理想情况下:
id | esz | 代码 | 排名 | 时间 |
---|---|---|---|---|
1 | 1 | “SOM” | 1 | 5 |
2 | 1 | “奎” | 2 | 空 |
3 | 1 | “版本” | 3 | 10 |
4 | 1 | “国家安全委员会” | 4 | 15 |
5 | 1 | “3SM” | 99 | 空 |
6 | 2 | “奎” | 1 | 7 |
7 | 2 | “版本” | 2 | 空 |
8 | 2 | “SOM” | 3 | 空 |
9 | 2 | “国家安全委员会” | 4 | 12 |
10 | 2 | “3SM” | 99 | 空 |
11 | 3 | “国家安全委员会” | 1 | 空 |
12 | 3 | “版本” | 2 | 空 |
13 | 3 | “奎” | 3 | 11 |
14 | 3 | “SOM” | 4 | 12 |
15 | 3 | “3SM” | 99 | 空 |
16 | 4 | “SOM” | 1 | 2 |
17 | 4 | “奎” | 2 | 空 |
18 | 4 | “国家安全委员会” | 3 | 3 |
19 | 4 | “版本” | 4 | 空 |
20 | 4 | “3SM” | 99 | 空 |
21 | 5 | “国家安全委员会” | 1 | 空 |
22 | 5 | “SOM” | 2 | 4 |
23 | 5 | “版本” | 3 | 空 |
24 | 5 | “奎” | 4 | 7 |
25 | 5 | “3SM” | 99 | 空 |
输出示例:
id | esz | 代码 | 排名 | 时间 |
---|---|---|---|---|
1 | 1 | “SOM” | 1 | 5 |
2 | 1 | “奎” | 2 | 6 |
3 | 1 | “版本” | 3 | 10 |
4 | 1 | “国家安全委员会” | 4 | 15 |
5 | 1 | “3SM” | 99 | 16 |
6 | 2 | “奎” | 1 | 7 |
7 | 2 | “版本” | 2 | 8 |
8 | 2 | “SOM” | 3 | 9 |
9 | 2 | “国家安全委员会” | 4 | 12 |
10 | 2 | “3SM” | 99 | 13 |
11 | 3 | “国家安全委员会” | 1 | 9 |
12 | 3 | “版本” | 2 | 10 |
13 | 3 | “奎” | 3 | 11 |
14 | 3 | “SOM” | 4 | 12 |
15 | 3 | “3SM” | 99 | 13 |
16 | 4 | “SOM” | 1 | 2 |
17 | 4 | “奎” | 2 | 2 |
18 | 4 | “国家安全委员会” | 3 | 3 |
19 | 4 | “版本” | 4 | 4 |
20 | 4 | “3SM” | 99 | 5 |
21 | 5 | “国家安全委员会” | 1 | 3 |
22 | 5 | “SOM” | 2 | 4 |
23 | 5 | “版本” | 3 | 5 |
24 | 5 | “奎” | 4 | 7 |
25 | 5 | “3SM” | 99 | 8 |
我可以使用 LAG() 和 LEAD() 以及 CASE 处理表中的大多数情况。但我对其中一些仍然有问题:例如 id=11 和 id=12。要么我必须从 id=13 的值向后退,要么我必须知道在填充 id=11 时我必须留下一个可用于填充 id=12 的值。
尝试使用完整的数据集:
with data(id, esz, code, rank, time) as (
select 1, 1, 'SOM', 1, 5 from dual union all
select 2, 1, 'QUI', 2, NULL from dual union all
select 3, 1, 'VER', 3, 10 from dual union all
select 4, 1, 'NSC', 4, 15 from dual union all
select 5, 1, '3SM', 99, NULL from dual union all
select 6, 2, 'QUI', 1, 7 from dual union all
select 7, 2, 'VER', 2, NULL from dual union all
select 8, 2, 'SOM', 3, NULL from dual union all
select 9, 2, 'NSC', 4, 12 from dual union all
select 10, 2, '3SM', 99, NULL from dual union all
select 11, 3, 'NSC', 1, NULL from dual union all
select 12, 3, 'VER', 2, NULL from dual union all
select 13, 3, 'QUI', 3, 11 from dual union all
select 14, 3, 'SOM', 4, 12 from dual union all
select 15, 3, '3SM', 99, NULL from dual union all
select 16, 4, 'SOM', 1, 2 from dual union all
select 17, 4, 'QUI', 2, NULL from dual union all
select 18, 4, 'NSC', 3, 3 from dual union all
select 19, 4, 'VER', 4, NULL from dual union all
select 20, 4, '3SM', 99, NULL from dual union all
select 21, 5, 'NSC', 1, NULL from dual union all
select 22, 5, 'SOM', 2, 4 from dual union all
select 23, 5, 'VER', 3, NULL from dual union all
select 24, 5, 'QUI', 4, 7 from dual union all
select 25, 5, '3SM', 99, NULL from dual
)
select d.id, d.esz, d.code, d.rank,
nvl(time,
case when ntime-ndelta < ptime+pdelta
then
ntime-ndelta
else
nvl(ptime+pdelta, ntime-ndelta)
end
) as time
from (
select d.*,
row_number() over(partition by esz, grp order by rank) as pdelta,
row_number() over(partition by esz, grp order by rank desc) as ndelta
from (
select d.*,
nvl(time, last_value(time ignore nulls) over(partition by esz order by rank
rows between unbounded preceding and 1 preceding))
as ptime,
rank - sum(nvl2(time,null,1)) over(partition by esz order by rank) as grp,
nvl(time, first_value(time ignore nulls) over(partition by esz order by rank
rows between 1 following and unbounded following) )
as ntime
from data d
) d
) d
order by esz, rank
;
1 1 SOM 1 5
2 1 QUI 2 6
3 1 VER 3 10
4 1 NSC 4 15
5 1 3SM 99 16
6 2 QUI 1 7
7 2 VER 2 8
8 2 SOM 3 9
9 2 NSC 4 12
10 2 3SM 99 13
11 3 NSC 1 9
12 3 VER 2 10
13 3 QUI 3 11
14 3 SOM 4 12
15 3 3SM 99 13
16 4 SOM 1 2
17 4 QUI 2 2
18 4 NSC 3 3
19 4 VER 4 5
20 4 3SM 99 4
21 5 NSC 1 3
22 5 SOM 2 4
23 5 VER 3 6
24 5 QUI 4 7
25 5 3SM 99 8