获取MySQL表中一个子类型的所有祖先/超类型

huangapple go评论58阅读模式
英文:

Getting all ancestors/ Super types of a descendent/ Sub type from table in MySQL

问题

我有一个包含层次数据的表格,看起来像这样:

ObjectType ObjectSubType
Everything Solid
Solid Solid
Solid Metal
Metal Metal
Metal Iron
Iron Iron

我正在尝试获取任何给定ObjectSubType的所有祖先/上级对象。

所以,如果我想要获取Iron的所有父级,它会看起来像这样:
Iron, Metal, Solid, Everything

我尝试使用递归,参考了这个链接

递归代码如下:

WITH RECURSIVE
  ancestorCategories  AS
  (
    SELECT ObjectType, ObjectSubType, 0 AS depth
      FROM ObjectTypeHierarchyTable
      WHERE ObjectType = "Iron"
    UNION ALL
    SELECT c.ObjectType, c.ObjectSubType, ac.depth - 2
      FROM ancestorCategories AS ac 
        JOIN ObjectTypeHierarchyTable AS c ON ac.ObjectSubType = c.ObjectType
  )
SELECT * FROM ancestorCategories;

然而,这似乎不起作用(可能缺少终止条件?)- 在db-fiddle上尝试时,我收到了以下错误消息:

递归查询在1001次迭代后中止。尝试增加@@cte_max_recursion_depth的值。

任何帮助都将不胜感激!

英文:

I have a table with hierarchical data that looks like this:

ObjectType ObjectSubType
Everything Solid
Solid Solid
Solid Metal
Metal Metal
Metal Iron
Iron Iron

I'm trying to get all the ancestors/supertypes of any given objectSubType.

so if I want all the parents of Iron, it would look something like this:
Iron, Metal, Solid, Everything

I've tried using recursion by referring this

recursion code:

WITH RECURSIVE
  ancestorCategories  AS
  (
    SELECT ObjectType, ObjectSubType, 0 AS depth
      FROM ObjectTypeHierarchyTable
      WHERE ObjectType = "Iron"
    UNION ALL
    SELECT c.ObjectType, c.ObjectSubType, ac.depth - 2
      FROM ancestorCategories AS ac 
        JOIN ObjectTypeHierarchyTable AS c ON ac.ObjectSubType = c.ObjectType
  )
SELECT * FROM ancestorCategories;

This does not seem to work though (possibly missing a termination condition?) - I get this error message when trying it out on db-fiddle:

> Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value.

Any help is appreciated!

答案1

得分: 1

没有使用递归解决,而是使用了WHILE循环和临时表来获取所有祖先:

DELIMITER $$
CREATE PROCEDURE get_ancestors(IN value VARCHAR(50))
BEGIN
  -- 创建一个临时表来保存祖先,一旦创建就清空它
  CREATE TABLE IF NOT EXISTS ancestors (
    ObjectType VARCHAR(50) NOT NULL
  );
  TRUNCATE TABLE ancestors;
  -- 将初始值插入到祖先表中
  INSERT INTO ancestors (ObjectType) VALUES (value);
  
  -- 循环直到不再找到祖先为止
  SET @new_rows = 1;
  SET @iterations = 0;
  SET @max_iterations = 100;
  WHILE (@new_rows > 0) AND (@iterations < @max_iterations) DO
      INSERT INTO ancestors (ObjectType)
      SELECT DISTINCT ObjectType
      FROM ObjectTypeHierarchyTable
      WHERE ObjectSubType IN (SELECT ObjectType FROM ancestors) 
      AND ObjectType NOT IN (SELECT ObjectType FROM ancestors);
      
      SET @new_rows = ROW_COUNT();
      SET @iterations = @iterations + 1;
  END WHILE;

  -- 从临时表中选择祖先
  SELECT * FROM ancestors;
END$$
DELIMITER ;

CALL get_ancestors('Metal');

也使用了一个过程来包装WHILE语句,因为不能直接使用WHILE语句。

根据MySQL的类型和版本,可以选择在创建ancestors表时使用TEMPORARY关键字(这在我的用例中适用于PyMySQL)。

英文:

Didn't solve it using recursion but managed to use a WHILE loop and a temporary table to get all the ancestors:

DELIMITER $$
CREATE PROCEDURE get_ancestors(IN value VARCHAR(50))
BEGIN
  -- create a temporary table to hold the ancestors, once and truncate it
  CREATE TABLE IF NOT EXISTS ancestors (
    ObjectType VARCHAR(50) NOT NULL
  );
  TRUNCATE TABLE ancestors;
  -- insert the initial value into the ancestors table
  INSERT INTO ancestors (ObjectType) VALUES (value);
  
  -- Loop until no more ancestors are found
  SET @new_rows = 1;
  SET @iterations = 0;
  SET @max_iterations = 100;
  WHILE (@new_rows &gt; 0) AND (@iterations &lt; @max_iterations) DO
      INSERT INTO ancestors (ObjectType)
      SELECT DISTINCT ObjectType
      FROM ObjectTypeHierarchyTable
      WHERE ObjectSubType IN (SELECT ObjectType FROM ancestors) 
      AND ObjectType NOT IN (SELECT ObjectType FROM ancestors);
      
      SET @new_rows = ROW_COUNT();
      SET @iterations = @iterations + 1;
  END WHILE;

  -- select the ancestors from the temporary table
  SELECT * FROM ancestors;
END$$
DELIMITER ;

CALL get_ancestors(&#39;Metal&#39;);

A procedure is also being used to wrap the WHILE statement because WHILE statements can't be used directly.

Optionally TEMPORARY keyword can be used while creating the ancestors table depending on the type and version of MySQL(it works in PyMySQL which is my use-case).

huangapple
  • 本文由 发表于 2023年1月9日 13:58:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75053639.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定