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

Posted

技术标签:

【中文标题】视图需要相互依赖的逻辑:没有模型可能吗?【英文标题】:View Requires Interdependence Logic: Possible without MODEL? 【发布时间】:2015-02-12 17:03:05 【问题描述】:

我正在尝试编写一些 Oracle 11g SQL,但我遇到了一些先有鸡还是先有蛋的问题。我正在寻找类似电子表格的行为。我找到了一个使用 Oracle 的 MODEL 子句的解决方案,但性能不是很好。所以我想知道“非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);

我想计算另外两个派生列,将它们称为 XY

以下是计算 XY 的规则:

X: 对于由 ID 的最小值定义的第一行,将X 设置为N。 对于所有后续行,X 的值应比前一个Y 的值小一,按ID 排序。

是的: 两次N 加上X

接下来的几个步骤展示了如果我要手动填写我想要的视图。首先,给定数据的前几行:

 ID    N    X    Y
---  ---  ---  ---
  2    0
  3    1
  5    1
  7    2
....

因为我们在第一行,所以X 应该设置为N0Y 应该是 2 * N + X0

 ID    N    X    Y
---  ---  ---  ---
  2    0    0    0
  3    1
  5    1
  7    2
....

现在,由于我们不再位于第一行,因此从现在开始,X 应该始终比上一行的 Y 小一个。在第二行中,这意味着 X = (previous 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

考虑到如何计算XY 的规则,是否有可能在不必诉诸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>

谢谢。

【问题讨论】:

【参考方案1】:

您可以使用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 

SQL Fiddle.

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

您的示例数据没有显着的性能差异,但是添加一千行后,模型子句大约需要 5 秒,递归 CTE 大约需要 1 秒;另一个千行模型需要约 20 秒,CTE 需要约 3 秒;另一个千行模型耗时约 40 秒,CTE 耗时约 6 秒;再加上一千行(总共 4,008 行),模型耗时约 75 秒,CTE 耗时约 10 秒。 (我厌倦了等待比这更多行的模型版本;五分钟后用 10,000 杀了它)。我真的不能说这将如何处理你的真实数据,但在此基础上,它可能值得一试。

【讨论】:

以前没听说过“递归 CTE”。像冠军一样工作,在 40% 的时间内运行!谢谢,亚历克斯普尔!

以上是关于视图需要相互依赖的逻辑:没有模型可能吗?的主要内容,如果未能解决你的问题,请参考以下文章

2个页面可以使用相同的视图模型吗?

我们可以在一个视图中使用不同模型的多个局部视图吗?

我可以有一个没有模型的 Django 表单吗

使用 Unity 进行 MVVM 依赖注入,用于分层视图模型

控制器内部应该写啥逻辑?

创建不需要模型的 Rails 视图 + 控制器?