问题描述
我想编写一个查询,该查询标识满足条件的有序集合中的“下一个”值。 LEAD / LAG解析函数在这里似乎不适用,因为要向前看的行数根据条件是可变的(不固定)。下面的示例显示了来自示例表(tbl)的所需结果(列gnme),但是解决方案似乎并不理想。希望这里的某人可能对这种问题有更优雅的解决方案。预先感谢。
请注意,在本示例中,第1-3行如何标识第4行中的nme
迈克,第6-7行如何标识nme
michael 在第8行中。
create table tbl (
id number,nme varchar(255)
)
;
insert into tbl (id,nme) values (1,'unknown');
insert into tbl (id,nme) values (2,nme) values (3,nme) values (4,'mike');
insert into tbl (id,nme) values (5,nme) values (6,nme) values (7,nme) values (8,'michael');
insert into tbl (id,nme) values (9,nme) values (10,nme) values (11,'unknown');
select
id,nme,CASE WHEN nme = 'unknown' THEN
NVL
(
(SELECT b.nme
FROM tbl b
WHERE
b.nme <> 'unknown'
AND a.id < b.id
ORDER BY id
OFFSET 0 ROWS FETCH NEXT 1 ROW ONLY
),nme
)
ELSE nme
END AS gnme
FROM
tbl a
;
+----+---------+---------+
| id | nme | gnme |
+----+---------+---------+
| 1 | unknown | mike |
+----+---------+---------+
| 2 | unknown | mike |
+----+---------+---------+
| 3 | unknown | mike |
+----+---------+---------+
| 4 | mike | mike |
+----+---------+---------+
| 5 | mike | mike |
+----+---------+---------+
| 6 | unknown | michael |
+----+---------+---------+
| 7 | unknown | michael |
+----+---------+---------+
| 8 | michael | michael |
+----+---------+---------+
| 9 | michael | michael |
+----+---------+---------+
| 10 | michael | michael |
+----+---------+---------+
| 11 | unknown | unknown |
+----+---------+---------+
解决方法
当名称未知时,您需要下一个非未知名称。
Oracle是少数支持窗口功能ignore nulls
和lead()
的{{1}}选项的数据库之一。这是一项强大的功能,在您的用例中很方便:
lag()
select
id,nme,case when nme = 'unknown'
then lead(nullif(nme,'unknown') ignore nulls,1,'unknown') over(order by id)
else nme
end gnme
from tbl
中的case
表达式将值lead()
变为'unknow'
,然后该函数带来下一个非null
值(如果存在,则默认为unknown没有可用。)
您可以使用first_value
分析函数:
select
id,nvl(
first_value(nullif(nme,'unknown') ignore nulls)over(order by id ROWS between current row and unbounded following),'unknown')
AS gnme
FROM
tbl a
;
完整示例进行比较:
select
id,CASE WHEN nme = 'unknown' THEN
NVL
(
(SELECT b.nme
FROM tbl b
WHERE
b.nme <> 'unknown'
AND a.id < b.id
ORDER BY id
OFFSET 0 ROWS FETCH NEXT 1 ROW ONLY
),nme
)
ELSE nme
END AS gnme,'unknown')
AS gnme_2
FROM
tbl a
;
结果:
ID NME GNME GNME_2
---------- ---------- ---------- ----------
1 unknown mike mike
2 unknown mike mike
3 unknown mike mike
4 mike mike mike
5 mike mike mike
6 unknown michael michael
7 unknown michael michael
8 michael michael michael
9 michael michael michael
10 michael michael michael
11 unknown unknown unknown
11 rows selected.
,
您也可以只将LAST_VALUE()与IGNORE NULL一起使用:
WITH
-- your input
tbl(id,nme) AS (
SELECT 1,'unknown'
UNION ALL SELECT 2,'unknown'
UNION ALL SELECT 3,'unknown'
UNION ALL SELECT 4,'mike'
UNION ALL SELECT 5,'mike'
UNION ALL SELECT 6,'unknown'
UNION ALL SELECT 7,'unknown'
UNION ALL SELECT 8,'michael'
UNION ALL SELECT 9,'michael'
UNION ALL SELECT 10,'michael'
UNION ALL SELECT 11,'unknown'
)
SELECT
*,NVL(
LAST_VALUE(NULLIF(nme,'unknown') IGNORE NULLS) OVER(
ORDER BY id DESC
),'unknown'
) AS gnme
FROM tbl
ORDER BY id;
-- out id | nme | gnme
-- out ----+---------+---------
-- out 1 | unknown | mike
-- out 2 | unknown | mike
-- out 3 | unknown | mike
-- out 4 | mike | mike
-- out 5 | mike | mike
-- out 6 | unknown | michael
-- out 7 | unknown | michael
-- out 8 | michael | michael
-- out 9 | michael | michael
-- out 10 | michael | michael
-- out 11 | unknown | unknown