【问题标题】:How to represent a limited-depth/width set of hierarchical data in MySQL如何在 MySQL 中表示有限深度/宽度的分层数据集
【发布时间】:2012-09-03 09:08:07
【问题描述】:

我正在尝试重构和规范 MySQL 中的产品表,如下所示:

CREATE TABLE `products` (
`id` varchar(45) NOT NULL, # alphanumeric product codes
`productCategory` varchar(45) NOT NULL, 
`productSubCategory` varchar(45) DEFAULT NULL, 
`productRange` varchar(45) NOT NULL,
`productClass` varchar(45) DEFAULT NULL,
`name` text NOT NULL,
`size` int(11) NOT NULL,
`sizeMeasure` varchar(5) NOT NULL,
`boxQuantity` int(11) NOT NULL,
`sellingPrice` double NOT NULL,
`rrp` double DEFAULT NULL,
`ordinalValue` int(11) NOT NULL,
PRIMARY KEY (`id`)
)

我认为需要重构的是productCategoryproductSubCategoryproductRange 字段。这样做的原因是我需要能够获得类别的层次结构。还计划将元数据添加到类别中。

表格字段目前包含的数据如下:

productCategory     productSubCategory      productRange
---------------------------------------------------------
retail              retail_solution1        retail_solution1_range1
retail              retail_solution2        retail_solution2_range2
retail              retail_solution3        retail_solution3_range3
professional        prof_solution1          prof_solution1_range1
professional        prof_solution1          prof_solution1_range2
professional        prof_solution1          prof_solution1_range3
professional        prof_solution2          prof_solution2_range1
professional        prof_solution2          prof_solution2_range2
professional        prof_solution2          prof_solution2_range3
...                 ...                     ...

基本上在productCategory RETAIL 集中,productSubCategoryproductRange 字段具有相同的VARCHAR(45) 值。

这棵树的深度在未来极不可能发生变化。最常见的更改可能是类别名称。

我查看了邻接表和嵌套集模型,不知何故感觉更倾向于使用嵌套集模型。


到目前为止我对嵌套集模型方法的了解:

添加类别:

CREATE PROCEDURE `addCategory`(IN parent VARCHAR(45), IN child VARCHAR(45))
BEGIN
    SELECT @myLeft := lft FROM product_category

    WHERE name = parent LIMIT 1;

    UPDATE product_category SET rgt = rgt + 2 WHERE rgt > @myLeft;
    UPDATE product_category SET lft = lft + 2 WHERE lft > @myLeft;

    INSERT INTO product_category(name, lft, rgt) VALUES(child, @myLeft + 1, @myLeft + 2);
END

删除一个类别:

CREATE PROCEDURE `deleteCategory`(IN name VARCHAR(45))
BEGIN
    SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
    FROM product_category
    WHERE name = name;

    DELETE FROM product_category WHERE lft BETWEEN @myLeft AND @myRight;

    UPDATE product_category SET rgt = rgt - @myWidth WHERE rgt > @myRight;
    UPDATE product_category SET lft = lft - @myWidth WHERE lft > @myRight;
END

我希望在 java web 应用程序中使用 sql,而不是存储过程。我使用 Spring 的 JDBCTemplate 进行所有数据访问。目前我不太确定如何处理这个问题,因为我之前没有使用JDBCTemplate 的多语句查询。

理想情况下,我还想使用 DBUnit 测试数据访问层。

让我对这个项目感到失望的是,不知何故,我觉得需要更加重视顶级类别。或许 RETAIL 和 PROFESSIONAL 的顶级类别应该是产品类型而不是类别?

任何指导将不胜感激。谢谢。

【问题讨论】:

    标签: sql database-design spring-data


    【解决方案1】:

    哦,好吧,这看起来很难看。

    首先,您应该使用类别 ID 将它们存储到您的产品中(而不是 varchars),接下来我将使用类别本身的简单分层设置。

    如果您只能有两个级别(产品要么属于根类别本身,要么属于其子类别之一) 只需执行以下操作:

    categoryID, name, parentId:
    1, sports, NULL
    2, Crossbows, 1
    3, Golf, 1
    4, Healthcare, NULL
    

    这里的运动和医疗保健是“大师”级别,就像您的零售和专业人士一样。

    如果你可以有更深的结构,我会考虑使用不同的方法,因为在大多数数据库中,多级层次结构是一件很痛苦的事情,espec。在mysql中(oracle有CONNECT BY PRIOR命令反对/为此)

    如果是这种情况,我会将完整路径存储在一个字符串中,就像操作系统一样 (root/subcat1/subcat2...),当某些内容被更新时,这可能会变得有些粘滞,但在检索时会非常快层次结构的完全递归检索。

    另一个讨论这个检索问题的话题How to do MySQL Looped Join which tests if results are complete?(需要代码)

    在您将类别解析为 ID 后,只需将特定(且唯一的)ID 作为外键存储在产品本身中。

    【讨论】:

    • 谢谢@najzero。确实是一团糟!
    • 澄清一下,我将使用类别 ID 作为产品表中的外键。顶部的 DDL 用于当前的表。您描述邻接列表模型的方法是什么?重新排序类别是否比在 Java 代码中的嵌套集合模型中更难?可能会有大约 40 个类别,深度仅为 3。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多