【问题标题】:CONCAT all parents of categoryCONCAT 类别的所有父项
【发布时间】:2014-05-13 21:39:39
【问题描述】:

示例数据库(嵌套集模型中的类别):

CREATE TABLE `category` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) NOT NULL DEFAULT '',
    `lft` int(11) NOT NULL,
    `rgt` int(11) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;

INSERT INTO category(name, lft, rgt) values("Primary", 0, 1000);
INSERT INTO category(name, lft, rgt) values("Secondary", 1, 500);
INSERT INTO category(name, lft, rgt) values("Tertiary", 2, 20);
INSERT INTO category(name, lft, rgt) values("Tertiary2", 21, 30);

我想像这样获取底部子类别的所有父母(可能是 concat?):

Primary > Secondary > Tertiary
Primary > Secondary > Tertiary2

除了玩 BETWEEN lft AND rgt 和 CONCAT 之外,我还很困惑,可以使用一些技巧和信息来获得所需的结果。谢谢!

SQL Fiddle

【问题讨论】:

  • 阅读 Bill Karwins 的幻灯片到SQL antipatterns,尤其是第 67 张幻灯片。
  • 得承认我没有看到层次结构。鉴于 lft 和 rgt 值,我看不到您如何从中学到小学,也看不到如何从第三中学到中学。某种递归 cte 可能会起作用,但我认为 mysql 不支持这样的分层查询......
  • 如果我不能从中得到所需的结果,当前的数据库结构对我来说毫无用处。如果您有需要更改数据库表的解决方案,我仍然非常希望看到它们。

标签: mysql sql hierarchical-data nested-sets nested-set-model


【解决方案1】:

下面的查询怎么样?

SELECT 
  GROUP_CONCAT(parent.name SEPARATOR '/') as parent_name
FROM category AS node,
        category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.lft;

将返回请求的输出:

Primary
Primary > Secondary
Primary > Secondary > Tertiary
Primary > Secondary > Tertiary2

可测试@http://sqlfiddle.com/#!9/4f4e97/2

如果你只想要叶子节点

如果我正确阅读了原始问题,您的预期输出应该是:

Primary > Secondary > Tertiary
Primary > Secondary > Tertiary2

通过将上述查询稍微修改为以下内容,也可以轻松实现:

SELECT 
  GROUP_CONCAT(parent.name SEPARATOR '/') as parent_name
FROM category AS node,
        category AS parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.lft, node.rgt
HAVING node.lft = (node.rgt - 1)
ORDER BY node.lft;

然而,这假设您的所有叶节点(它们应该)都具有 rgt = lft + 1 !!

测试@http://sqlfiddle.com/#!9/57acd4/1

【讨论】:

    【解决方案2】:

    查看 Mike Hillyer 在 Managing Heirarchial Data 上的这篇精彩文章。

    它解释了一种很好的方法,不仅可以结构化数据,还可以查询和操作数据,包括邻接表模型和嵌套集模型之间的一些差异。

    • 表结构
    • 如何通过各种方式查询
      • 查找节点、路径和完整树结果
    • 处理新数据的插入
    • 处理数据删除

    最后,我意识到本文没有明确回答您直接在 SQL 中生成此类结果的要求。

    Primary > Secondary > Tertiary
    Primary > Secondary > Tertiary2
    

    如果没有昂贵的循环或非常难以维护的查询,您可能不会找到任何关于这样做的好方法。

    通常这是在应用程序级别完成的,因为通常这些语言更适合它(当您可以查询数据时,您可以生成深度值,这使得这种循环非常容易做到)。

    【讨论】:

    • 您对这个解决方案有什么想法? karwin.blogspot.nl/2010/03/…
    • 闭包表不是一个糟糕的解决方案,并且确实有一些好处,如该链接和上面的链接中所述,我假设在@VMai 提到它们并且您跳过他的评论后发现它们不合适。
    • 我还不确定。我将尝试使用 Closure Tables,并按照您的建议从我当前的数据库中用 PHP 构建数据。这是关系设计第一次对我不利,所以我正在探索我的选择和有更多经验的人的意见。
    • 闭包模型将允许您保持引用完整性并使节点的 CRUD 更容易一些。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    • 2017-12-21
    相关资源
    最近更新 更多