【问题标题】:sql - Get top parent of specified recordsql - 获取指定记录的最高父级
【发布时间】:2018-06-19 08:49:04
【问题描述】:

我有一个标准的嵌套类别树:

| id | parent_id |      name      |
+----+-----------+----------------+
|  1 |     0     |   Category 1   |
|  2 |     0     |   Category 2   |
|  3 |     0     |   Category 3   |
|  4 |     1     |  Category 1.1  |
|  5 |     1     |  Category 1.2  |
|  6 |     2     |  Category 2.1  |
|  7 |     2     |  Category 2.2  |
|  8 |     7     | Category 2.2.1 |

现在我需要获取指定项目的最高父级,所以我这样做:

SELECT
    cat.*
FROM
    categories cat
LEFT JOIN
    categories subCat
    ON
        subCat.parent_id = cat.id
        AND cat.parent_id = 0
WHERE
    subCat.id = 5;

如果 item 是一级子项,它工作正常,但 item 是二级子项(例如 8)我没有得到记录 - 怎么做?
这里是 SQlFiddle:http://sqlfiddle.com/#!9/5879bd/11

更新 这是一个真实的例子:http://sqlfiddle.com/#!9/6f1d1c/1
我想得到Xiaomi的父类别

【问题讨论】:

  • 有了那个样本表数据,预期的结果是什么?
  • @jarlh 我更新了问题
  • 您使用哪个版本的 MySQL?树的最大深度是否存在?如果是,是哪个?
  • @stickybit : MySQL 5.6,是的——树的最大深度为 3

标签: mysql sql


【解决方案1】:

在 MySQL 5.6 中,您不能使用递归 CTE。

要正确地做到这一点,对于任意树深度,您需要编写一个函数/过程,它遍历层次结构并在到达时返回顶部节点。

作为一种解决方法,当设置了最大级别 d 数时,您可以左加入父级 (d - 1) 次。使用coalesce() 获取路径上的第一个非空值。所以在你的情况下,对于 d = 3:

SELECT c.*
       FROM categories c
            INNER JOIN (SELECT coalesce(c3.id, c2.id, c1.id) id
                               FROM categories c1
                                    LEFT JOIN categories c2
                                              ON c2.id = c1.parent_id
                                    LEFT JOIN categories c3
                                              ON c3.id = c2.parent_id
                               WHERE c1.id = 10) t
                       ON t.id = c.id;

(我首先选择顶部节点的 ID,然后将其余部分内连接,以避免在所有列上出现 coalesce()。如果顶部节点中的列的值为 null 但它可能会在可空列上给出错误结果,但不适用于任何子节点。它应该显示NULL,但会错误地显示来自子节点的非值。)

但请注意:如果深度增加,它将失败!

【讨论】:

  • 效果很好,谢谢! “使用 MySQL 5.6,您不能使用递归 CTE。” - 所以这是 MySQL 5.7 的另一种方式?
  • @Paul:MySQL 8.0 引入了该功能。
【解决方案2】:

这回答了问题的原始版本。

要获得顶层,您可以使用name 列:

SELECT c.*
FROM categories c JOIN
     categories sc
     ON sc.id = 10 AND
        c.name = SUBSTRING_INDEX(sc.name, '.', 1);

【讨论】:

  • 看起来不错,但这些类别名称只是示例。它可以用于例如Electronics > Hardware > HDD - 它没有任何 1.1 等。
  • @Paul 。 . .然后用合适的样本数据问另一个问题。只能提出您实际提出的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 2013-01-05
相关资源
最近更新 更多