考虑一个博客应用程序,其中包含用于将帖子与一个或多个类别相关联的帖子,类别和查找表的表格。类别是分层的。帖子可以分配给任何类别,而不仅仅是叶子节点。
类别表有一个post_count
字段,用于缓存分配给特定类别的帖子数。对于MPTT,它还有parent_id
,lft
和rght
列。
但它还有一个under_post_count
字段,用于缓存分配给它或其任何子类别的不同帖子的数量。这非常有用,因此您可以显示分类的分层列表,其中包含分配给它的帖子数,或其中一个子,旁边。
我的应用已达到这样的程度,即在使用类别创建帖子后,或者编辑了类别或删除了类别的类别后,我会列出新旧类别的类别ID列表,其{{1字段需要更新。我希望接下来可以做的是单个查询,更新所有已识别类别的post_count
字段及其所有父母,其中包含分配给每个类别或其中任何类别的不同帖子的数量子
这是创建表所需的SQL和类别的一些测试数据:
under_post_count
运行此几次以为CREATE TABLE `categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`lft` int(11) DEFAULT NULL,
`rght` int(11) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`post_count` int(11) NOT NULL DEFAULT '0',
`under_post_count` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
CREATE TABLE `categories_posts` (
`category_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
PRIMARY KEY (`category_id`,`post_id`)
) ENGINE=MyISAM;
INSERT INTO `categories` (`id`, `parent_id`, `lft`, `rght`, `name`) VALUES
(1, NULL, 1, 8, 'Cat 1'),
(4, 1, 2, 3, 'Cat 1.1'),
(5, 1, 4, 5, 'Cat 1.2'),
(6, 1, 6, 7, 'Cat 1.3'),
(2, NULL, 9, 16, 'Cat 2'),
(7, 2, 10, 11, 'Cat 2.1'),
(8, 2, 12, 13, 'Cat 2.2'),
(9, 2, 14, 15, 'Cat 2.3'),
(3, NULL, 17, 24, 'Cat 3'),
(10, 3, 18, 19, 'Cat 3.1'),
(11, 3, 20, 21, 'Cat 3.2'),
(12, 3, 22, 23, 'Cat 3.3');
表创建一些测试数据:
categories_posts
任何人都可以理解这一点,你的帮助会非常感激吗?
答案 0 :(得分:3)
有很多方法可以让猫在这里(假设5.1和触发器)
您可以从应用层
您可以从post_count
触发categories_posts
的更新,并从under_post_count
categories
最后,您可以从categories_posts
同样取决于实际的类别数量,您可能不需要对under_post_count
进行非规范化,因为使用
SELECT c.id, SUM(cc.post_count)
FROM categories c
LEFT JOIN categories cc ON c.lft <= cc.lft AND c.rght >= cc.rght
GROUP BY c.id;
获取完全匹配的实际计数是
SELECT c.id, COUNT(*)
FROM categories c
LEFT JOIN categories_posts cp ON c.id = cp.post_id
GROUP BY c.id;
将两者结合起来可以得出包括层次结构在内的计数
SELECT c.id, COUNT(*)
FROM categories c
LEFT JOIN categories cc ON c.lft <= cc.lft AND c.rght >= cc.rght
LEFT JOIN categories_posts cp ON cc.id = cp.post_id
GROUP BY c.id;
修改强>
从上面构建更新语句不应该那么难
UPDATE categories
SET post_count = (SELECT COUNT(*)
FROM categories_posts cp
WHERE cp.post_id = categories.id)
适用于post_count
under_post_count
的情况不同,因为mysql不喜欢听到where部分中提到的目标表,因此你必须像这样做一些怪物
UPDATE categories LEFT JOIN
(SELECT c.id, COUNT(*) AS result
FROM categories c
LEFT JOIN categories cc ON c.lft <= cc.lft AND c.rght >= cc.rght
INNER JOIN categories_posts cp ON cc.id = cp.post_id
GROUP BY c.id) AS x ON categories.id = x.id
SET under_post_count = x.result
<强> EDIT2 强>
实际上,上述所有查询都存在错误 - 每当我加入类别和帖子时,我应该加入cc.id = cp.category_id
而不是cp.post_id
,然后我就不会检查。不想纠正......但仅限于最后一次查询
UPDATE categories LEFT JOIN
(SELECT c.id, COUNT(*) AS result
FROM categories c
LEFT JOIN categories cc ON c.lft <= cc.lft AND c.rght >= cc.rght
INNER JOIN categories_posts cp ON cc.id = cp.category_id
INNER JOIN posts p ON cp.post_id = p.id
WHERE p.status = 'published'
GROUP BY c.id) AS x ON categories.id = x.id
SET under_post_count = x.result,
post_count = (SELECT COUNT(*)
FROM categories_posts cp
WHERE cp.category_id = categories.id)
<强> EDIT3 强>
只有几点说明:
under_post_count
和post_count
,无论数据的状态如何,post_count = post_count +/- 1
(类似于{{1} }),