【问题标题】:How to resolve SQL id chain?如何解析 SQL id 链?
【发布时间】:2014-07-04 02:57:59
【问题描述】:

我有一个带有这样的表的 MySQL 数据库:

|编号 |重定向 | +--------+----------+ | 1 |空 | | 2 | 3 | | 3 |空 | | 4 | 5 | | 5 | 6 | | 6 | 8 | | 7 |空 | | 8 |空 | +--------+----------+

我需要为递归解析重定向创建查询。 所以我可以得到结果:

1 1 2 3 3 3 4 8 5 8 6 8 7 7 8 8

谢谢

【问题讨论】:

  • OP的从起始ID到左节点之后,如果没有叶子节点,则自引用。
  • 我不确定它是否可以通过单个查询来解决,但为什么不在数据库输入时解决它。
  • @Satwik Nadkarny:这确实有道理。这些行“必须为 8”,因为 8 是以 4 开头的路径的终止节点,它也是以 5 开头并以 6 开头的路径的终止节点。
  • 存储的过程可以调用自身(递归)。存储过程递归由系统变量max_sp_recursion_depth 控制。存储的 函数 不能是递归的,因此您可以创建一个调用递归存储过程的函数。您也不一定必须使用递归。您可以在存储函数或过程中使用 WHILE 循环。查看类似内容:stackoverflow.com/questions/3438111/…

标签: mysql sql


【解决方案1】:

一种方法是使用单独的查询来获取每个“级别”。

要获得第一级,我们可以在 redirect_id 列中测试 NULL 以识别“终止”节点。

要获得第二级,我们可以使用 JOIN 操作来匹配具有 redirect_id 的行,该行与“终止”行中的 id 匹配(之前已确定)。

第三层遵循相同的模式,添加另一个 JOIN 操作以返回重定向到第二层行的行。

等等。

例如:

SELECT t1.id  AS start_id
     , t1.id  AS terminate_id
  FROM mytable t1
 WHERE t1.redirect_id IS NULL

 UNION ALL

SELECT t2.id
     , t1.id
  FROM mytable t1
  JOIN mytable t2 ON t2.redirect_id = t1.id
 WHERE t1.redirect_id IS NULL

 UNION ALL

SELECT t3.id
     , t1.id
  FROM mytable t1
  JOIN mytable t2 ON t2.redirect_id = t1.id
  JOIN mytable t3 ON t3.redirect_id = t2.id
 WHERE t1.redirect_id IS NULL


 UNION ALL

SELECT t4.id
     , t1.id
  FROM mytable t1
  JOIN mytable t2 ON t2.redirect_id = t1.id
  JOIN mytable t3 ON t3.redirect_id = t2.id
  JOIN mytable t4 ON t4.redirect_id = t3.id
 WHERE t1.redirect_id IS NULL

这种单一查询UNION ALL 方法的局限性在于它需要扩展到有限的最大级别数。 (这种方法并不是真正的“递归”。)

如果我们需要一种真正的递归方法,我们可以单独运行每个查询,只需按照相同的模式为每次运行添加一个额外的“级别”。当查询的结果没有返回任何行时,我们就知道我们已经用尽了所有可能的路径。

我已经演示了使用UNION ALL 运算符将结果组合到一个集合中,使用单个查询。 (如果行的顺序很重要,请在语句末尾添加 ORDER BY 子句。在结果集中包含文字“级别”列也很容易,例如 1 AS level 用于第一个 SELECT,@ 987654326@ 用于第二个查询等,以识别节点与终端的距离。

MySQL 不支持 Oracle 风格的 CONNECT BY 语法(在 Oracle 中,我们可以编写一个查询来遍历这个集合并返回指定的行,任意数量的级别。)

要在 MySQL 中获得真正的“递归”方法,需要多次查询。 (请注意,如果服务器配置为允许,MySQL 可以在存储过程调用中支持“递归”。)

【讨论】:

    猜你喜欢
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多