假设我有3个表(仅限有效列)
key
,parentCatId)key
,parentTrail,catLevel)key
,catId,createdOn)有一个单独的Category_Hierarchy表是有原因的,因为我正在使用填充它的Category表上的触发器,因为MySql触发器正如他们那样工作,如果我愿意,我无法在触发器内的同一个表上填充列使用auto_increment
值。为了这个问题,这是无关紧要的。无论如何,这两个表格是1:1。
类别表可以是:
+-------+-------------+
| catId | parentCatId |
+-------+-------------+
| 1 | NULL |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 3 |
| 6 | 4 |
| ... | ... |
+-------+-------------+
Category_Hierarchy
+-------+-------------+----------+
| catId | parentTrail | catLevel |
+-------+-------------+----------+
| 1 | 1/ | 0 |
| 2 | 1/2/ | 1 |
| 3 | 1/2/3/ | 2 |
| 4 | 1/2/3/4/ | 3 |
| 5 | 1/2/3/5/ | 3 |
| 6 | 1/2/3/4/6/ | 4 |
| ... | ... | ... |
+-------+-------------+----------+
产品
+--------+-------+---------------------+
| prodId | catId | createdOn |
+--------+-------+---------------------+
| 1 | 4 | 2010-02-03 12:09:24 |
| 2 | 4 | 2010-02-03 12:09:29 |
| 3 | 3 | 2010-02-03 12:09:36 |
| 4 | 1 | 2010-02-03 12:09:39 |
| 5 | 3 | 2010-02-03 12:09:50 |
| ... | ... | ... |
+--------+-------+---------------------+
Category_Hierarchy使得获取类别从属树变得如此简单:
select c.*
from Category c
join Category_Hierarchy h
on (h.catId = c.catId)
where h.parentTrail like '1/2/3/%'
哪个将返回类别3的完整从属树(低于2,即低于1,这是根类别),包括从属树根节点。排除根节点只是一个where
条件。
我想写一个存储过程:
create procedure GetLatestProductsFromSubCategories(in catId int)
begin
/* return 10 latest products from each */
/* catId subcategory subordinate tree */
end;
这意味着如果某个类别有3个直接子类别(下面有任意数量的节点),我将得到30个结果(每个从属树有10个)。如果它有5个子类别,我会得到50个结果。
最好/最快/最有效的方法是什么?如果可能的话,我希望避免使用游标,除非它们比任何其他解决方案以及准备好的语句更快地工作,因为这将是对DB最频繁的调用之一。
由于一张图片告诉1000个单词,我会尝试用图像更好地解释我想要的东西。下图显示了类别树。 每个节点都可以拥有与之相关的任意数量的产品。产品不包括在图片中。
category tree http://i50.tinypic.com/1sfnmv.jpg
所以,如果我执行此调用:
call GetLatestProductsFromSubCategories(1);
我想有效地获得30种产品:
我不想从catId=1
节点下的每个节点获得10个最新产品,这意味着320个产品。
答案 0 :(得分:2)
此解决方案具有O(n)性能:
CREATE PROCEDURE foo(IN in_catId INT)
BEGIN
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE first_iteration BOOLEAN DEFAULT TRUE;
DECLARE current VARCHAR(255);
DECLARE categories CURSOR FOR
SELECT parentTrail
FROM category
JOIN category_hierarchy USING (catId)
WHERE parentCatId = in_catId;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE;
SET @query := '';
OPEN categories;
category_loop: LOOP
FETCH categories INTO current;
IF `done` THEN LEAVE category_loop; END IF;
IF first_iteration = TRUE THEN
SET first_iteration = FALSE;
ELSE
SET @query = CONCAT(@query, " UNION ALL ");
END IF;
SET @query = CONCAT(@query, "(SELECT product.* FROM product JOIN category_hierarchy USING (catId) WHERE parentTrail LIKE CONCAT('",current,"','%') ORDER BY createdOn DESC LIMIT 10)");
END LOOP category_loop;
CLOSE categories;
IF @query <> '' THEN
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END
由于最新的澄清,此解决方案只是编辑,以简化类别光标查询。
注意:根据您的parentTrail列,使第5行的VARCHAR成为合适的大小。