具有动态参数的 Oracle 滞后函数
Oracle Lag function with dynamic parameter
我有一个具体问题。我有一个包含无效值的 table。
我需要用大于 0
.
的先前值替换无效值(此处 0
)
问题是,我不适合使用 Update 或 insert(Cursor 和 update 就可以)。我唯一的方法是使用 Select 语句。
当我将 lag(col1, 1)
- 函数与 when case 一起使用时,我只得到一列具有正确的值。
select col1, col2 realcol2,
(case
when col2 = 0 then
lag(col2,1,1) over (partition by col1 order by col1 )
else
col2
end ) col2,
col3 realcol3,
(case
when col3 = 0 then
lag(col3,1,1) over (partition by col1 order by col1 )
else
col3
end ) col3
from test_table
TEST_TABLE
的内容:
---------------------------
Col1 | Col2 | Col3 | Col4
---------------------------
A | 0 | 1 | 5
B | 0 | 4 | 0
C | 2 | 0 | 0
D | 0 | 0 | 0
E | 3 | 5 | 0
F | 0 | 3 | 0
G | 0 | 3 | 1
A | 0 | 1 | 5
E | 3 | 5 | 0
预期查询结果:
---------------------------
Col1 | Col2 | Col3 | Col4
---------------------------
A | 0 | 1 | 5
B | 0 | 4 | 5
C | 2 | 4 | 5
D | 2 | 4 | 5
E | 3 | 5 | 5
F | 3 | 3 | 5
G | 3 | 3 | 1
A | 3 | 1 | 5
E | 3 | 5 | 5
假设您想要 以前的 值根据您的原始数据顺序(无论可能是什么),那么您的查询可能看起来像:
with preserve_the_order$ as (
select X.*,
rownum as original_order$
from test_table X
)
select X.col1,
nvl(last_value(case when col2 > 0 then col2 end) ignore nulls over (order by original_order$ rows between unbounded preceding and current row), col2) as col2,
nvl(last_value(case when col3 > 0 then col3 end) ignore nulls over (order by original_order$ rows between unbounded preceding and current row), col3) as col3,
nvl(last_value(case when col4 > 0 then col4 end) ignore nulls over (order by original_order$ rows between unbounded preceding and current row), col4) as col4
from preserve_the_order$ X
order by original_order$
;
结果:
COL1 COL2 COL3 COL4
---- ---------- ---------- ----------
A 0 1 5
B 0 4 5
C 2 4 5
D 2 4 5
E 3 5 5
F 3 3 5
G 3 3 1
A 0 1 5
E 3 5 5
我假设有一个额外的列 col0
,其中包含一个明显的数据排序标准,因为您的 col1
示例数据没有真正正确排序([= 的重复、尾随值14=] 和 E
).
出于这些目的,我喜欢 MODEL
子句。以下查询产生预期结果:
WITH t(col0, col1, col2, col3, col4) AS (
SELECT 1, 'A', 0, 1, 5 FROM DUAL UNION ALL
SELECT 2, 'B', 0, 4, 0 FROM DUAL UNION ALL
SELECT 3, 'C', 2, 0, 0 FROM DUAL UNION ALL
SELECT 4, 'D', 0, 0, 0 FROM DUAL UNION ALL
SELECT 5, 'E', 3, 5, 0 FROM DUAL UNION ALL
SELECT 6, 'F', 0, 3, 0 FROM DUAL UNION ALL
SELECT 7, 'G', 0, 3, 1 FROM DUAL UNION ALL
SELECT 8, 'A', 0, 1, 5 FROM DUAL UNION ALL
SELECT 9, 'E', 3, 5, 0 FROM DUAL
)
SELECT * FROM t
MODEL
DIMENSION BY (row_number() OVER (ORDER BY col0) rn)
MEASURES (col1, col2, col3, col4)
RULES (
col2[any] = DECODE(col2[cv(rn)], 0, NVL(col2[cv(rn) - 1], 0), col2[cv(rn)]),
col3[any] = DECODE(col3[cv(rn)], 0, NVL(col3[cv(rn) - 1], 0), col3[cv(rn)]),
col4[any] = DECODE(col4[cv(rn)], 0, NVL(col4[cv(rn) - 1], 0), col4[cv(rn)])
)
结果:
RN COL1 COL2 COL3 COL4
1 A 0 1 5
2 B 0 4 5
3 C 2 4 5
4 D 2 4 5
5 E 3 5 5
6 F 3 3 5
7 G 3 3 1
8 A 3 1 5
9 E 3 5 5
关于 MODEL 子句与 window 基于函数的方法的说明
虽然上面看起来很酷(或可怕,取决于您的观点),但您当然应该更喜欢使用 window 基于函数的方法,正如 or . I've explained these answers more in detail in this blog post 的其他优雅答案所揭示的那样。
SELECT col1,
CASE col2 WHEN 0 THEN NVL( LAG( CASE col2 WHEN 0 THEN NULL ELSE col2 END ) IGNORE NULLS OVER ( ORDER BY NULL ), 0 ) ELSE col2 END AS col2,
CASE col3 WHEN 0 THEN NVL( LAG( CASE col3 WHEN 0 THEN NULL ELSE col3 END ) IGNORE NULLS OVER ( ORDER BY NULL ), 0 ) ELSE col3 END AS col3,
CASE col4 WHEN 0 THEN NVL( LAG( CASE col4 WHEN 0 THEN NULL ELSE col4 END ) IGNORE NULLS OVER ( ORDER BY NULL ), 0 ) ELSE col4 END AS col4
FROM table_name;
结果:
COL1 COL2 COL3 COL4
---- ---------- ---------- ----------
A 0 1 5
B 0 4 5
C 2 4 5
D 2 4 5
E 3 5 5
F 3 3 5
G 3 3 1
A 3 1 5
E 3 5 5
我有一个具体问题。我有一个包含无效值的 table。
我需要用大于 0
.
0
)
问题是,我不适合使用 Update 或 insert(Cursor 和 update 就可以)。我唯一的方法是使用 Select 语句。
当我将 lag(col1, 1)
- 函数与 when case 一起使用时,我只得到一列具有正确的值。
select col1, col2 realcol2,
(case
when col2 = 0 then
lag(col2,1,1) over (partition by col1 order by col1 )
else
col2
end ) col2,
col3 realcol3,
(case
when col3 = 0 then
lag(col3,1,1) over (partition by col1 order by col1 )
else
col3
end ) col3
from test_table
TEST_TABLE
的内容:
---------------------------
Col1 | Col2 | Col3 | Col4
---------------------------
A | 0 | 1 | 5
B | 0 | 4 | 0
C | 2 | 0 | 0
D | 0 | 0 | 0
E | 3 | 5 | 0
F | 0 | 3 | 0
G | 0 | 3 | 1
A | 0 | 1 | 5
E | 3 | 5 | 0
预期查询结果:
---------------------------
Col1 | Col2 | Col3 | Col4
---------------------------
A | 0 | 1 | 5
B | 0 | 4 | 5
C | 2 | 4 | 5
D | 2 | 4 | 5
E | 3 | 5 | 5
F | 3 | 3 | 5
G | 3 | 3 | 1
A | 3 | 1 | 5
E | 3 | 5 | 5
假设您想要 以前的 值根据您的原始数据顺序(无论可能是什么),那么您的查询可能看起来像:
with preserve_the_order$ as (
select X.*,
rownum as original_order$
from test_table X
)
select X.col1,
nvl(last_value(case when col2 > 0 then col2 end) ignore nulls over (order by original_order$ rows between unbounded preceding and current row), col2) as col2,
nvl(last_value(case when col3 > 0 then col3 end) ignore nulls over (order by original_order$ rows between unbounded preceding and current row), col3) as col3,
nvl(last_value(case when col4 > 0 then col4 end) ignore nulls over (order by original_order$ rows between unbounded preceding and current row), col4) as col4
from preserve_the_order$ X
order by original_order$
;
结果:
COL1 COL2 COL3 COL4
---- ---------- ---------- ----------
A 0 1 5
B 0 4 5
C 2 4 5
D 2 4 5
E 3 5 5
F 3 3 5
G 3 3 1
A 0 1 5
E 3 5 5
我假设有一个额外的列 col0
,其中包含一个明显的数据排序标准,因为您的 col1
示例数据没有真正正确排序([= 的重复、尾随值14=] 和 E
).
出于这些目的,我喜欢 MODEL
子句。以下查询产生预期结果:
WITH t(col0, col1, col2, col3, col4) AS (
SELECT 1, 'A', 0, 1, 5 FROM DUAL UNION ALL
SELECT 2, 'B', 0, 4, 0 FROM DUAL UNION ALL
SELECT 3, 'C', 2, 0, 0 FROM DUAL UNION ALL
SELECT 4, 'D', 0, 0, 0 FROM DUAL UNION ALL
SELECT 5, 'E', 3, 5, 0 FROM DUAL UNION ALL
SELECT 6, 'F', 0, 3, 0 FROM DUAL UNION ALL
SELECT 7, 'G', 0, 3, 1 FROM DUAL UNION ALL
SELECT 8, 'A', 0, 1, 5 FROM DUAL UNION ALL
SELECT 9, 'E', 3, 5, 0 FROM DUAL
)
SELECT * FROM t
MODEL
DIMENSION BY (row_number() OVER (ORDER BY col0) rn)
MEASURES (col1, col2, col3, col4)
RULES (
col2[any] = DECODE(col2[cv(rn)], 0, NVL(col2[cv(rn) - 1], 0), col2[cv(rn)]),
col3[any] = DECODE(col3[cv(rn)], 0, NVL(col3[cv(rn) - 1], 0), col3[cv(rn)]),
col4[any] = DECODE(col4[cv(rn)], 0, NVL(col4[cv(rn) - 1], 0), col4[cv(rn)])
)
结果:
RN COL1 COL2 COL3 COL4
1 A 0 1 5
2 B 0 4 5
3 C 2 4 5
4 D 2 4 5
5 E 3 5 5
6 F 3 3 5
7 G 3 3 1
8 A 3 1 5
9 E 3 5 5
关于 MODEL 子句与 window 基于函数的方法的说明
虽然上面看起来很酷(或可怕,取决于您的观点),但您当然应该更喜欢使用 window 基于函数的方法,正如
SELECT col1,
CASE col2 WHEN 0 THEN NVL( LAG( CASE col2 WHEN 0 THEN NULL ELSE col2 END ) IGNORE NULLS OVER ( ORDER BY NULL ), 0 ) ELSE col2 END AS col2,
CASE col3 WHEN 0 THEN NVL( LAG( CASE col3 WHEN 0 THEN NULL ELSE col3 END ) IGNORE NULLS OVER ( ORDER BY NULL ), 0 ) ELSE col3 END AS col3,
CASE col4 WHEN 0 THEN NVL( LAG( CASE col4 WHEN 0 THEN NULL ELSE col4 END ) IGNORE NULLS OVER ( ORDER BY NULL ), 0 ) ELSE col4 END AS col4
FROM table_name;
结果:
COL1 COL2 COL3 COL4
---- ---------- ---------- ----------
A 0 1 5
B 0 4 5
C 2 4 5
D 2 4 5
E 3 5 5
F 3 3 5
G 3 3 1
A 3 1 5
E 3 5 5