View 需要相互依赖的逻辑:没有 MODEL 可能吗?
View Requires Interdependence Logic: Possible without MODEL?
我正在尝试编写一些 Oracle 11g SQL,但我 运行 遇到了一些先有鸡还是先有蛋的问题。我正在寻找类似电子表格的行为。我找到了一个确实使用 Oracle 的 MODEL
子句的解决方案,但性能不是很好。所以我想知道 "non-MODEL
" 解决方案在技术上是否可行。
这是一个演示我正在尝试做的事情的玩具示例。鉴于此 table:
CREATE TABLE t (id NUMBER PRIMARY KEY, n NUMBER);
INSERT INTO t (id, n) VALUES (2, 0);
INSERT INTO t (id, n) VALUES (3, 1);
INSERT INTO t (id, n) VALUES (5, 1);
INSERT INTO t (id, n) VALUES (7, 2);
INSERT INTO t (id, n) VALUES (11, 3);
INSERT INTO t (id, n) VALUES (13, 5);
INSERT INTO t (id, n) VALUES (17, 8);
INSERT INTO t (id, n) VALUES (19, 13);
我想计算两个额外的派生列,将它们命名为 X
和 Y
。
以下是 X
和 Y
的计算规则:
X:
For the very first row, as defined by the minimum value of ID, set X
to N
.
For all subsequent rows, the value of X
should be one less than the value of the previous Y
, as sorted by ID
.
Y:
Twice N
plus X
.
接下来的几个步骤展示了如果我手动完成此操作,我将如何填写我想要的视图。首先,给定数据的前几行:
ID N X Y
--- --- --- ---
2 0
3 1
5 1
7 2
....
因为我们在第一行,所以 X
应该设置为 N
,或者 0
。 Y
应该是 2 * N + X
,或者 0
。
ID N X Y
--- --- --- ---
2 0 0 0
3 1
5 1
7 2
....
现在,由于我们不再位于第一行,从现在开始,X
应该总是比前一行的 Y
少一个。在第二行,这意味着 X
=(之前的 Y
)- 1
= 0 - 1
= -1
。第二行的 Y
将是 2 * N + X
,或 2 * (1) + (-1)
= 1
.
ID N X Y
--- --- --- ---
2 0 0 0
3 1 -1 1
5 1
7 2
....
如果您继续进行数学计算,这是您想要的结果:
ID N X Y
--- --- --- ---
2 0 0 0
3 1 -1 1
5 1 0 2
7 2 1 5
11 3 4 10
13 5 9 19
17 8 18 34
19 13 33 59
鉴于 X
和 Y
的计算规则,是否有可能在不求助于 MODEL
子句的情况下获得此结果?
我不是在寻找基于这个特定示例的数学简化;这只是我提出的一个玩具示例,它展示了我在实际问题中面临的那种相互依赖关系。
P.S.: 这是一个 MODEL
示例,我能够拼凑出这个输出;也许可以进行修改以提高性能?
SQL> WITH u AS (
2 SELECT ROW_NUMBER() OVER (ORDER BY t.id) r
3 , t.id
4 , t.n
5 FROM t
6 )
7 SELECT r
8 , id
9 , n
10 , x
11 , y
12 FROM u
13 MODEL
14 DIMENSION BY (r)
15 MEASURES (id
16 , n
17 , CAST(NULL AS NUMBER) x
18 , CAST(NULL AS NUMBER) y) RULES AUTOMATIC ORDER
19 ( x[1] = n[cv()]
20 , y[r] = 2 * n[cv()] + x[cv()]
21 , x[r > 1] ORDER BY r = y[cv() - 1] - 1
22 )
23 ;
R ID N X Y
---------- ---------- ---------- ---------- ----------
1 2 0 0 0
2 3 1 -1 1
3 5 1 0 2
4 7 2 1 5
5 11 3 4 10
6 13 5 9 19
7 17 8 18 34
8 19 13 33 59
8 rows selected.
SQL>
谢谢。
您可以使用 recursive subquery factoring(也称为递归 CTE):
with tmp as (
select t.*,
row_number() over (order by t.id) as rn
from t
),
r (id, n, x, y, rn) as (
select id, n, 0, 0, rn
from tmp
where rn = 1
union all
select tmp.id, tmp.n, r.y - 1, (tmp.n * 2) + r.y - 1, tmp.rn
from r
join tmp on tmp.rn = r.rn + 1
)
select id, n, x, y
from r
order by rn;
ID N X Y
---------- ---------- ---------- ----------
2 0 0 0
3 1 -1 1
5 1 0 2
7 2 1 5
11 3 4 10
13 5 9 19
17 8 18 34
19 13 33 59
它基本上是在完成您的手动步骤。锚成员是您的第一个手动步骤,将第一行的 x
和 y
都设置为零。然后递归成员执行您指定的计算。 (在计算该行的 y
时,您不能引用新计算的 x
值,因此您必须将其重复为 (tmp.n * 2) + r.y - 1
)。 rn
只是为了让行按 ID 排序,同时更容易找到下一行 - 因此您可以查找 rn + 1
而不是直接找到下一个最高 ID 值。
与您的示例数据没有显着的性能差异,但是添加一千行模型子句大约需要 5 秒,递归 CTE 大约需要 1 秒;使用另一个千行模型需要大约 20 秒,而 CTE 需要大约 3 秒;另一个千行模型耗时约 40 秒,CTE 耗时约 6 秒;再有 1000 行(总共 4,008 行)模型耗时约 75 秒,CTE 耗时约 10 秒。 (我厌倦了等待比这更多行的模型版本;五分钟后用 10,000 杀死了它)。我真的不能说这将如何处理您的真实数据,但在此基础上,它可能值得尝试。
我正在尝试编写一些 Oracle 11g SQL,但我 运行 遇到了一些先有鸡还是先有蛋的问题。我正在寻找类似电子表格的行为。我找到了一个确实使用 Oracle 的 MODEL
子句的解决方案,但性能不是很好。所以我想知道 "non-MODEL
" 解决方案在技术上是否可行。
这是一个演示我正在尝试做的事情的玩具示例。鉴于此 table:
CREATE TABLE t (id NUMBER PRIMARY KEY, n NUMBER);
INSERT INTO t (id, n) VALUES (2, 0);
INSERT INTO t (id, n) VALUES (3, 1);
INSERT INTO t (id, n) VALUES (5, 1);
INSERT INTO t (id, n) VALUES (7, 2);
INSERT INTO t (id, n) VALUES (11, 3);
INSERT INTO t (id, n) VALUES (13, 5);
INSERT INTO t (id, n) VALUES (17, 8);
INSERT INTO t (id, n) VALUES (19, 13);
我想计算两个额外的派生列,将它们命名为 X
和 Y
。
以下是 X
和 Y
的计算规则:
X: For the very first row, as defined by the minimum value of ID, set
X
toN
. For all subsequent rows, the value ofX
should be one less than the value of the previousY
, as sorted byID
.Y: Twice
N
plusX
.
接下来的几个步骤展示了如果我手动完成此操作,我将如何填写我想要的视图。首先,给定数据的前几行:
ID N X Y
--- --- --- ---
2 0
3 1
5 1
7 2
....
因为我们在第一行,所以 X
应该设置为 N
,或者 0
。 Y
应该是 2 * N + X
,或者 0
。
ID N X Y
--- --- --- ---
2 0 0 0
3 1
5 1
7 2
....
现在,由于我们不再位于第一行,从现在开始,X
应该总是比前一行的 Y
少一个。在第二行,这意味着 X
=(之前的 Y
)- 1
= 0 - 1
= -1
。第二行的 Y
将是 2 * N + X
,或 2 * (1) + (-1)
= 1
.
ID N X Y
--- --- --- ---
2 0 0 0
3 1 -1 1
5 1
7 2
....
如果您继续进行数学计算,这是您想要的结果:
ID N X Y
--- --- --- ---
2 0 0 0
3 1 -1 1
5 1 0 2
7 2 1 5
11 3 4 10
13 5 9 19
17 8 18 34
19 13 33 59
鉴于 X
和 Y
的计算规则,是否有可能在不求助于 MODEL
子句的情况下获得此结果?
我不是在寻找基于这个特定示例的数学简化;这只是我提出的一个玩具示例,它展示了我在实际问题中面临的那种相互依赖关系。
P.S.: 这是一个 MODEL
示例,我能够拼凑出这个输出;也许可以进行修改以提高性能?
SQL> WITH u AS (
2 SELECT ROW_NUMBER() OVER (ORDER BY t.id) r
3 , t.id
4 , t.n
5 FROM t
6 )
7 SELECT r
8 , id
9 , n
10 , x
11 , y
12 FROM u
13 MODEL
14 DIMENSION BY (r)
15 MEASURES (id
16 , n
17 , CAST(NULL AS NUMBER) x
18 , CAST(NULL AS NUMBER) y) RULES AUTOMATIC ORDER
19 ( x[1] = n[cv()]
20 , y[r] = 2 * n[cv()] + x[cv()]
21 , x[r > 1] ORDER BY r = y[cv() - 1] - 1
22 )
23 ;
R ID N X Y
---------- ---------- ---------- ---------- ----------
1 2 0 0 0
2 3 1 -1 1
3 5 1 0 2
4 7 2 1 5
5 11 3 4 10
6 13 5 9 19
7 17 8 18 34
8 19 13 33 59
8 rows selected.
SQL>
谢谢。
您可以使用 recursive subquery factoring(也称为递归 CTE):
with tmp as (
select t.*,
row_number() over (order by t.id) as rn
from t
),
r (id, n, x, y, rn) as (
select id, n, 0, 0, rn
from tmp
where rn = 1
union all
select tmp.id, tmp.n, r.y - 1, (tmp.n * 2) + r.y - 1, tmp.rn
from r
join tmp on tmp.rn = r.rn + 1
)
select id, n, x, y
from r
order by rn;
ID N X Y
---------- ---------- ---------- ----------
2 0 0 0
3 1 -1 1
5 1 0 2
7 2 1 5
11 3 4 10
13 5 9 19
17 8 18 34
19 13 33 59
它基本上是在完成您的手动步骤。锚成员是您的第一个手动步骤,将第一行的 x
和 y
都设置为零。然后递归成员执行您指定的计算。 (在计算该行的 y
时,您不能引用新计算的 x
值,因此您必须将其重复为 (tmp.n * 2) + r.y - 1
)。 rn
只是为了让行按 ID 排序,同时更容易找到下一行 - 因此您可以查找 rn + 1
而不是直接找到下一个最高 ID 值。
与您的示例数据没有显着的性能差异,但是添加一千行模型子句大约需要 5 秒,递归 CTE 大约需要 1 秒;使用另一个千行模型需要大约 20 秒,而 CTE 需要大约 3 秒;另一个千行模型耗时约 40 秒,CTE 耗时约 6 秒;再有 1000 行(总共 4,008 行)模型耗时约 75 秒,CTE 耗时约 10 秒。 (我厌倦了等待比这更多行的模型版本;五分钟后用 10,000 杀死了它)。我真的不能说这将如何处理您的真实数据,但在此基础上,它可能值得尝试。