【问题标题】:MySQL: Find top/ultimate parentMySQL:查找顶级/最终父级
【发布时间】:2016-04-06 16:58:45
【问题描述】:

我发现了一些类似的东西,但都不是我需要的。

ID  |   PARENT
1   |   NULL
2   |   5
3   |   6
4   |   6
5   |   NULL
6   |   9
7   |   NULL
8   |   7
9   |   8
10  |   NULL

我有一个如下所示的表,需要使用 MySQL 查找最顶层的父级。我在这方面遇到的问题是,到达最高父级的层次结构步骤可能多达 20 个,我认为我对 MySQL 的了解还不够,无法弄清楚。

提前致谢!

【问题讨论】:

  • 那些以NULL为父母的人呢?
  • NULL 父级表示它是最顶层的父级。通常这将通过递归查询来完成(使用公用表表达式或在 oracle 中通过先验连接)但是,我的 SQL 没有这个。 mikehillyer.com/articles/managing-hierarchical-data-in-mysql 提供了一种方法,但我自己没有使用过。 stackoverflow.com/questions/3137674/… 也提供了一种方法。
  • 所谓的边或邻接列表对于无限或不确定深度的树来说并不是那么好。选项包括:尽可能频繁地将表连接到自身,创建一个存储过程来处理递归,在应用程序级代码中处理递归,或者切换到替代模型(例如嵌套集)

标签: mysql parent


【解决方案1】:

这是我的回答。它不是很好,但它的工作原理。第一个查询是针对带有序列引擎的 MariaDB,较长的是来自“普通”MySQL

开始参数(id)必须在这里设置@sid := 8

MariaDB

SELECT path, sid
FROM (
  SELECT *, @sid AS sid, @path := CONCAT(@path,' -> ', @sid) AS path,
  (SELECT (@sid:=parent) FROM mytab WHERE id = @sid) AS parent  
  FROM seq_1_to_99
  CROSS JOIN ( SELECT @sid := 8 , @path :=@sid) AS parameter
  HAVING parent = @sid
) AS result
ORDER BY seq DESC
LIMIT 1;

MySQL

SELECT path, sid FROM (
SELECT *, @sid AS sid,
 @path := CONCAT(@path,' -> ', @sid) AS PATH,
 (SELECT (@sid:=parent) FROM mytab WHERE id = @sid) AS parent

FROM (
  SELECT *
  FROM (
    SELECT d2.a*10+d1.a  AS nr
    FROM (
        SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
        SELECT 4   UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL
        SELECT 8   UNION ALL SELECT 9) AS d1
      CROSS JOIN (
        SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3  ) AS d2
  ) AS counter
  ORDER BY counter.nr
) AS result
CROSS JOIN ( SELECT @sid := 8 , @path :=@sid) AS parameter
HAVING parent = @sid
) AS p
ORDER BY nr DESC
LIMIT 1;

样本

MariaDB []> select * from mytab;
+----+--------+
| id | parent |
+----+--------+
|  1 |   NULL |
|  2 |      3 |
|  3 |   NULL |
|  4 |   NULL |
|  5 |      4 |
|  6 |      5 |
|  7 |      8 |
|  8 |      6 |
+----+--------+
8 rows in set (0.00 sec)

MariaDB []> SELECT path, sid
    -> FROM (
    ->   SELECT *, @sid AS sid, @path := CONCAT(@path,' -> ', @sid) AS path,
    ->   (SELECT (@sid:=parent) FROM mytab WHERE id = @sid) AS parent
    ->   FROM seq_1_to_99
    ->   CROSS JOIN ( SELECT @sid := 8 , @path :=@sid) AS parameter
    ->   HAVING parent = @sid
    -> ) AS result
    -> ORDER BY seq DESC
    -> LIMIT 1;
+-------------+------+
| path        | sid  |
+-------------+------+
| 8 -> 6 -> 4 | 4    |
+-------------+------+
1 row in set (0.01 sec)

MariaDB []> SELECT path, sid FROM (
    -> SELECT *, @sid AS sid,
    ->  @path := CONCAT(@path,' -> ', @sid) AS PATH,
    ->  (SELECT (@sid:=parent) FROM mytab WHERE id = @sid) AS parent
    ->
    -> FROM (
    ->   SELECT *
    ->   FROM (
    ->     SELECT d2.a*10+d1.a  AS nr
    ->     FROM (
    ->         SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
    ->         SELECT 4   UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL
    ->         SELECT 8   UNION ALL SELECT 9) AS d1
    ->       CROSS JOIN (
    ->         SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3  ) AS d2
    ->   ) AS counter
    ->   ORDER BY counter.nr
    -> ) AS result
    -> CROSS JOIN ( SELECT @sid := 8 , @path :=@sid) AS parameter
    -> HAVING parent = @sid
    -> ) AS p
    -> ORDER BY nr DESC
    -> LIMIT 1;
+-------------+------+
| path        | sid  |
+-------------+------+
| 8 -> 6 -> 4 |    4 |
+-------------+------+
1 row in set (0.01 sec)

MariaDB []>

希望对你有所帮助。

【讨论】:

  • “FROM seq_1_to_99”有什么用?
  • “序列引擎允许创建具有给定起始值、结束值和增量的数字(正整数)的升序或降序序列。”见:mariadb.com/kb/en/sequence-storage-engine
  • 好的,谢谢。可能这个疑问需要一个单独的问题。只是想知道它是否可能。我已经有一个包含@sid 或 8 的查询。那么是否可以合并两个查询并从此查询中返回根值以及另一个大选择查询?给我一个想法。
  • 您可以打开一个新问题或通过邮件向我发送查询。我的电子邮件在我的个人资料中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多