MySQL:类别树和 n 级产品

MySQL: Category Tree and Products in n levels

所以,假设我有一个 MySQL 数据库,其中包含以下表格:

产品

类别

为了让所有产品从某个类别 ID 下来,查询数据库的最佳方法是什么。例如,如果我有一个子类别树,其中基本类别 id = 1 如何获得 id =1 子类别下的所有产品以获得未确定数量的子类别.

我可以这样做:

SELECT * FROM `Product` WHERE category_id IN (
   SELECT `id` FROM `Category` WHERE parent_id = 1
)

然而,它只适用于类别 id = 1 的直接子级,而不适用于第 2 到 n 级子级。

谢谢。


编辑

有人建议阅读 a blog article 关于这个,我也看过那篇文章,我做了这个 sqlfiddle:

http://sqlfiddle.com/#!2/be72ec/1

正如您在查询中看到的,即使是他们教授的最简单的方法,获取类别树也不会输出任何内容。我错过了什么?其他方法也有同样的问题。

谢谢。

我查看了您的 sqlfiddle 并得出以下结论。

您的代码存在问题,您使用的是 NULL 值。 查看此 sqlfiddle 以查看工作示例:http://sqlfiddle.com/#!2/07ef7/1/0

我对您的陈述做了一些更正,现在一切正常。
这是我所做更改的列表:

  • 在 create 语句中将“parent_id bigint(11) unsigned DEFAULT NULL”更改为“parent_id bigint(11) unsigned NOT NULL DEFAULT 0”
  • 删除外键约束,但我没有使用“0”作为 parent_id
  • 插入“0”而不是 "NULL" 作为 parent_id
  • 将 FUNCTION 中的数据类型 INT 更改为 BIGINT,因为您在创建语句中使用了此类型
  • 从 select 语句中删除 WHERE 子句

希望对你有帮助!

以下是语句,以防 sqlfiddle 现在无法正常工作:

CREATE TABLE `Category` (
  `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  `parent_id` bigint(11) unsigned NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  KEY `parent_id` (`parent_id`),
  KEY `ix_hierarchy_parent` (`parent_id`, `id`)
)//


INSERT INTO `Category` (`id`, `name`, `parent_id`)
VALUES
    (1,'Cat Name 1',0),
    (2,'Cat Name 2',0),
    (3,'Cat Name 3',2),
    (4,'Cat Name 4',2),
    (7,'Cat Name 5',4),
    (8,'Cat Name 6',4),
    (9,'Cat Name 7',4),
    (10,'Cat Name 8',4),
    (11,'Cat Name 9',4),
    (12,'Cat Name 10',4),
    (13,'Cat Name 11',2),
    (16,'Cat Name 12',13),
    (17,'Cat Name 13',13),
    (18,'Cat Name 14',13),
    (19,'Cat Name 15',13),
    (20,'Cat Name 16',13),
    (21,'Cat Name 17',13)//


CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value BIGINT) RETURNS INT
NOT DETERMINISTIC
READS SQL DATA
BEGIN
        DECLARE _id BIGINT;
        DECLARE _parent_id BIGINT;
        DECLARE _next BIGINT;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL;

        SET _parent_id = @id;
        SET _id = -1;

        IF @id IS NULL THEN
                RETURN NULL;
        END IF;

        LOOP
                SELECT  MIN(id)
                INTO    @id
                FROM    `Category`
                WHERE   parent_id = _parent_id
                        AND id > _id;
                IF @id IS NOT NULL OR _parent_id = @start_with THEN
                        SET @level = @level + 1;
                        RETURN @id;
                END IF;
                SET @level := @level - 1;
                SELECT  id, parent_id
                INTO    _id, _parent_id
                FROM    `Category`
                WHERE   id = _parent_id;
        END LOOP;       
END//

SELECT  CONCAT(REPEAT('    ', level - 1), CAST(hi.id AS CHAR)) AS treeitem, hi.name, parent_id, level
FROM    (
        SELECT  hierarchy_connect_by_parent_eq_prior_id(id) AS id, @level AS level
        FROM    (
                SELECT  @start_with := 0,
                        @id := @start_with,
                        @level := 0
                ) vars, `Category`
        WHERE   @id IS NOT NULL
        ) ho
JOIN    `Category` hi
ON      hi.id = ho.id