Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 视图需要相互依赖逻辑:没有模型可能吗?_Sql_Oracle_Oracle11g - Fatal编程技术网

Sql 视图需要相互依赖逻辑:没有模型可能吗?

Sql 视图需要相互依赖逻辑:没有模型可能吗?,sql,oracle,oracle11g,Sql,Oracle,Oracle11g,我正试图编写一些Oracle 11g SQL,但我遇到了一个鸡和蛋的问题。我正在寻找类似电子表格的行为。我找到了一个使用Oracle的MODEL子句的解决方案,但性能不太好。所以我想知道“非模型”解决方案在技术上是否可行 这里有一个玩具的例子,演示了我正在尝试做什么。鉴于此表: CREATE TABLE t (id NUMBER PRIMARY KEY, n NUMBER); INSERT INTO t (id, n) VALUES (2, 0); INSERT INTO t (id, n) V

我正试图编写一些Oracle 11g SQL,但我遇到了一个鸡和蛋的问题。我正在寻找类似电子表格的行为。我找到了一个使用Oracle的
MODEL
子句的解决方案,但性能不太好。所以我想知道“非
模型
”解决方案在技术上是否可行

这里有一个玩具的例子,演示了我正在尝试做什么。鉴于此表:

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: 对于由ID的最小值定义的第一行,将
X
设置为
N
。 对于所有后续行,
X
的值应比前面的
Y
的值小一个,按
ID
排序

Y: 两次
N
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
的规则,是否有可能在不使用
模型
子句的情况下获得此结果

我不是在寻找基于这个特殊例子的数学简化;这只是我提出的一个玩具例子,它展示了我在实际问题中所面临的那种相互依赖

附言:这里有一个
模型
示例,我能够拼凑起来生成这个输出;也许有可能改进性能

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>
谢谢。

您可以使用(也称为递归CTE):

它基本上是通过你的手动步骤。锚定成员是您的第一个手动步骤,将第一行的
x
y
都设置为零。然后递归成员执行您指定的计算。(在计算该行的
y
时,不能引用新计算的
x
值,因此必须将其重复为
(tmp.n*2)+r.y-1
)。
rn
只是按ID保持行的顺序,同时更容易找到下一行-因此您可以查找
rn+1
,而不是直接查找下一个最高的ID值

示例数据的性能没有显著差异,但是添加了1000行之后,model子句大约需要5秒,递归CTE大约需要1秒;对于另一个千行模型,需要约20秒,CTE需要约3秒;再加上1000排,模型耗时约40秒,CTE耗时约6秒;再加上1000行(总共4008行),模型耗时约75秒,CTE耗时约10秒。(我等的模型版本行数比这多,我觉得很无聊;5分钟后,我就用10000行把它干掉了)。我真的不能说这将如何处理您的真实数据,但在此基础上,它可能值得一试。

以前从未听说过“递归CTE”。像冠军一样工作,跑了40%的时间!谢谢,亚历克斯·普尔!
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