使用 match_recognize 填写 "missing" 值
fill in "missing" values using match_recognize
,要求解决一个相当常见的用例,即用 [=66] 中的非 "missing" 值填充 "missing"(基于定义的缺失标准)值=](基于定义的排序标准)行。
我通常解决这个问题的方法是
- 将 "missing" 值重新映射 (
decode
/case
) 为 NULL,
- 在非 "missing" 值上使用
last_value()
分析函数,其中 ignore nulls
和 window 所有前面行的 window定义的顺序。
即,给定(取自原始 post)行 my_table
的输入集......
ORD COL1 COL2 COL3 COL4
--- ---- ---- ---- ----
1 A 0 1 5
2 B 0 4 0
3 C 2 0 0
4 D 0 0 0
5 E 3 5 0
6 F 0 3 0
7 G 0 3 1
8 A 0 1 5
9 E 3 5 0
...,order by ord asc
的排序,值为 "missing" 的标准是值为负数或零(case when colX <= 0 then null else colX end
for X
of { 2,3,4}), ...
的查询
select X.ord, X.col1,
nvl(last_value(case when col2 > 0 then col2 end) ignore nulls over (order by ord), col2) as col2,
nvl(last_value(case when col3 > 0 then col3 end) ignore nulls over (order by ord), col3) as col3,
nvl(last_value(case when col4 > 0 then col4 end) ignore nulls over (order by ord), col4) as col4
from my_table X
order by ord;
... 会产生期望的结果...
ORD 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
Lukas Eder proposed a beautiful alternative solution with the model
clause, working with the fact that the model
operation in his case works inductively(根据我对他查询的执行计划中的SQL MODEL ORDERED
操作的观察),从第一行到最后一行按照想要的顺序,得到行n
在处理行 n+1
时已经填写了 "missing" 值。
Lukas 的评论之一还提到了使用 Oracle 12c 的 match_recognize
子句的可能性。我试图让这个(对我来说是全新的)条款被理解并且工作失败了。所以,...
赏金邀请! :-)
我将悬赏小额奖励给针对上述问题的最优雅的基于 match_recognize
的解决方案。使用 pivot
、unpivot
、自连接、model
、分析、聚合、PL/SQL,随便什么,都是禁止的。只允许使用标准标量 SQL 函数。我对纯 match_recognize
在基础 my_table
数据源上工作很感兴趣。
我认为您无法使用纯 MATCH_RECOGNIZE
子句来完成结果。仅仅是因为值 col2
、col3
、col4
彼此独立,但模式是按整行计算的。因此,如果可以匹配多个符号(在您的情况下,多个列具有零值或非零值),则只有第一个作为分类器匹配,其他的将被忽略。
对于单列有一个简单的解决方案:
SELECT
ORD, COL1, COL2R COL2
FROM
my_table
MATCH_RECOGNIZE (
ORDER BY ORD
MEASURES
NVL(LAST(V2.COL2), 0) AS COL2R
ALL ROWS PER MATCH
PATTERN ((V20*V2+V20*)+)
DEFINE
V2 AS V2.COL2 > 0,
V20 AS V20.COL2 = 0
)
无论如何,解析函数绝对是您的最佳选择。 MODEL
和 MATCH_RECOGNIZE
子句旨在解决不同的问题,其中解析函数无济于事,尽管优化得很好,但两者都比解析函数更重。
模式中的 条件确实会针对整行进行评估,因此必须为每种可能性定义一个条件。然后,您可以使用 SUBSET 子句将适当的条件组合在一起。
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 col0, col1, C02, C03, C04
FROM t
match_recognize(
order by col0
measures nvl(C02.col2,0) C02,
nvl(C03.col3,0) C03,
nvl(C04.col4,0) C04
all rows per match
pattern ((C234|C23|C24|C34|C2|C3|C4|X)+)
subset C02 = (C234, C23, C24, C2),
C03 = (C234, C23, C34, C3),
C04 = (C234, C24, C34, C4)
define C234 as col2>0 and col3>0 and col4>0,
C23 as col2>0 and col3>0,
C24 as col2>0 and col4>0,
C34 as col3>0 and col4>0,
C2 as col2>0, C3 as col3>0, C4 as col4>0
);
我通常解决这个问题的方法是
- 将 "missing" 值重新映射 (
decode
/case
) 为 NULL, - 在非 "missing" 值上使用
last_value()
分析函数,其中ignore nulls
和 window 所有前面行的 window定义的顺序。
即,给定(取自原始 post)行 my_table
的输入集......
ORD COL1 COL2 COL3 COL4
--- ---- ---- ---- ----
1 A 0 1 5
2 B 0 4 0
3 C 2 0 0
4 D 0 0 0
5 E 3 5 0
6 F 0 3 0
7 G 0 3 1
8 A 0 1 5
9 E 3 5 0
...,order by ord asc
的排序,值为 "missing" 的标准是值为负数或零(case when colX <= 0 then null else colX end
for X
of { 2,3,4}), ...
select X.ord, X.col1,
nvl(last_value(case when col2 > 0 then col2 end) ignore nulls over (order by ord), col2) as col2,
nvl(last_value(case when col3 > 0 then col3 end) ignore nulls over (order by ord), col3) as col3,
nvl(last_value(case when col4 > 0 then col4 end) ignore nulls over (order by ord), col4) as col4
from my_table X
order by ord;
... 会产生期望的结果...
ORD 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
Lukas Eder proposed a beautiful alternative solution with the model
clause, working with the fact that the model
operation in his case works inductively(根据我对他查询的执行计划中的SQL MODEL ORDERED
操作的观察),从第一行到最后一行按照想要的顺序,得到行n
在处理行 n+1
时已经填写了 "missing" 值。
Lukas 的评论之一还提到了使用 Oracle 12c 的 match_recognize
子句的可能性。我试图让这个(对我来说是全新的)条款被理解并且工作失败了。所以,...
赏金邀请! :-)
我将悬赏小额奖励给针对上述问题的最优雅的基于 match_recognize
的解决方案。使用 pivot
、unpivot
、自连接、model
、分析、聚合、PL/SQL,随便什么,都是禁止的。只允许使用标准标量 SQL 函数。我对纯 match_recognize
在基础 my_table
数据源上工作很感兴趣。
我认为您无法使用纯 MATCH_RECOGNIZE
子句来完成结果。仅仅是因为值 col2
、col3
、col4
彼此独立,但模式是按整行计算的。因此,如果可以匹配多个符号(在您的情况下,多个列具有零值或非零值),则只有第一个作为分类器匹配,其他的将被忽略。
对于单列有一个简单的解决方案:
SELECT
ORD, COL1, COL2R COL2
FROM
my_table
MATCH_RECOGNIZE (
ORDER BY ORD
MEASURES
NVL(LAST(V2.COL2), 0) AS COL2R
ALL ROWS PER MATCH
PATTERN ((V20*V2+V20*)+)
DEFINE
V2 AS V2.COL2 > 0,
V20 AS V20.COL2 = 0
)
无论如何,解析函数绝对是您的最佳选择。 MODEL
和 MATCH_RECOGNIZE
子句旨在解决不同的问题,其中解析函数无济于事,尽管优化得很好,但两者都比解析函数更重。
模式中的 条件确实会针对整行进行评估,因此必须为每种可能性定义一个条件。然后,您可以使用 SUBSET 子句将适当的条件组合在一起。
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 col0, col1, C02, C03, C04
FROM t
match_recognize(
order by col0
measures nvl(C02.col2,0) C02,
nvl(C03.col3,0) C03,
nvl(C04.col4,0) C04
all rows per match
pattern ((C234|C23|C24|C34|C2|C3|C4|X)+)
subset C02 = (C234, C23, C24, C2),
C03 = (C234, C23, C34, C3),
C04 = (C234, C24, C34, C4)
define C234 as col2>0 and col3>0 and col4>0,
C23 as col2>0 and col3>0,
C24 as col2>0 and col4>0,
C34 as col3>0 and col4>0,
C2 as col2>0, C3 as col3>0, C4 as col4>0
);