如何在MySQL中表示有限深度/宽度的分层数据集

时间:2012-09-03 09:08:08

标签: sql database-design spring-data

我正在尝试重构和规范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零售集中,productSubCategoryproductRange字段具有相同的VARCHAR(45)值。

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

我查看了邻接列表和嵌套集模型,并且在某种程度上感觉更倾向于使用嵌套集模型。


到目前为止,嵌套集模型方法的目的是什么:

The Model

添加类别:

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的顶级类别应该是产品类型而不是类别?

非常感谢任何指导。感谢。

1 个答案:

答案 0 :(得分:0)

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

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

如果您只能有两个级别(该产品位于根类别本身或其子类别中) 只需执行以下操作:

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

在这里,体育和医疗保健是“主要”级别,就像您的零售和专业人士一样。

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

如果是这种情况,我会将完整路径存储在一个像操作系统那样的字符串中(root / subcat1 / subcat2 ...),当某些内容更新时,这可能会有点粘性,但反向速度非常快hirarchies的完全递归回顾。

讨论此追溯问题的另一个主题How to do MySQL Looped Join which tests if results are complete?(需要代码)

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