如何在每一步限制递归SELECT查询?

时间:2017-07-13 20:12:13

标签: sql recursion mariadb

我试图编写一个递归的SELECT查询来查看存储在数据库中的图形(MariaDB 10.2.6)。我的图表的节点标有两个坐标 - 让他们称之为x和y。构造图形使得在(x,y)和(x-1,y),(x,y-1)和(x-1,y-1)之间存在边缘。然后通过函数对每个边进行排序,该函数取决于与每个节点相关联的值的差异(例如,f(n1,n2)= n2.value-n1.value,其中n1和n2是共享边的两个节点)。 / p>

为了使这更复杂,假设边缘函数对于(x,y) - >的情况是不同的。 (x-1,y)比其他情况。为这种情况调用函数f1,对于其他情况调用f2。

我想要做的是根据以下规则从任意起点遍历此图:

  • x和y在步骤中可能永远不会增加;
  • 如果存在满足f1< 1的节点(x-1,y)。 (一些截止值),总是采取这一步;
  • 否则取(f,y-1)或(x-1,y-1)中的一个使f2最小化;
  • 如果(x,y-1)和(x-1,y-1)不存在,则回退到(x-1,y)。
  • 最后,如果没有合适的邻居,递归查询应该终止。

现在我正尝试使用递归SELECT查询,如下所示:

WITH RECURSIVE step (
  id,    -- step number
  tid,   -- substep number
  nid,   -- node id
  x,     -- node x
  y,     -- node y
  f      -- value of f between the previous and current nodes
)
AS
(
  -- Initial step.
  SELECT 1 AS id, 1 AS tid, n1.id AS nid, n1.x, n1.y, 0.0 AS f
  FROM nodes AS n1 WHERE n1.x = initial_x AND n1.y = initial_y

  -- Begin the recursive part.
  UNION ALL
    -- Use a subquery here so we can limit each step.
    SELECT * FROM (

    -- First part of the subquery checks (x-1,y).
    SELECT step.id + 1 AS id, 1 AS tid, n2.id AS nid,
           n2.x, n2.y, f1(v1.value, v2.value) AS f
    FROM step
    INNER JOIN values v1 ON v1.node = step.nid
    INNER JOIN nodes n2 ON (n2.x = step.x - 1 AND n2.y = step.y)
    INNER JOIN values v2 ON v2.node = n2.id
    WHERE f < some_cutoff

    -- Second part of the subquery checks (x,y-1) and (x-1,y-1).
    UNION
    SELECT step.id + 1 AS id, 2 AS tid, n2.id AS nid,
           n2.x, n2.y, f2(v1.value, v2.value) AS f
    FROM step
    INNER JOIN values v1 ON v1.node = step.nid
    INNER JOIN nodes n2 ON (n2.x = step.x AND n2.y = step.y - 1)
                        OR (n2.x = step.x - 1 AND n2.y = step.y - 1)
    INNER JOIN values v2 ON v2.node = n2.id

    -- Third part again selects (x-1,y) but without cutoff condition.
    UNION
    SELECT step.id + 1 AS id, 3 AS tid, n2.id AS nid,
           n2.x, n2.y, f1(v1.value, v2.value) AS f
    FROM step
    INNER JOIN values v1 ON v1.node = step.nid
    INNER JOIN nodes n2 ON n2.x = step.x - 1 AND n1.y = step.y
    INNER JOIN values v2 ON v2.node = n2.id

    ) a    -- give the subquery a dummy name

    -- At the end of the recursive step, sort and take the first step.
    ORDER BY tid, f ASC LIMIT 1

)

-- Get the list of steps.
SELECT * FROM step ORDER BY id ASC;

我的想法基本上是将三个条件分成三个联合子查询,每个子查询的等级(tid)都在增加。在每个递归步骤结束时,我按此等级排序,然后按每个等级中的f值排序。这应该给我留下一组行,最优选的节点位于顶部。最后,我使用LIMIT 1来选择最有利的节点,并继续递归。当我到达没有合适邻居的节点(x_min,y_min)时,子查询应该返回一个空集,并且递归应该终止。

不幸的是,这个查询现在对我不起作用。每当我尝试执行它时,MariaDB都会挂起,我不知道为什么。我明显的第一个想法是递归永远不会终止(无限循环),但我相信在减少的x和y上的INNER JOIN应该阻止这种情况。我错过了一些重要的事情/不了解如何正确使用递归查询?有没有更好的方法来解决这类问题?

0 个答案:

没有答案