正如标题所说,我有两个表,一个用于分类,另一个用于广告
ads table
id , cat_id
31 , 16
32 , 16
33 , 2
categories table
id , tree
1 , 0
2, 0
6, 0
13, 1
16, 6
17, 6
18, 6
我希望的结果是
category , num subcategories , num ads
1 , 1 , 0
2 , 0 , 1
6 , 3 , 2
我想得到树在0的位置(主要类别)。
答案 0 :(得分:1)
如果您只有2级层次结构,那么您可以这样做:
select
y.category,
coalesce(z.sub_category_count, 0) as num_sub_categories,
y.num_ads
from
(
select -- combine the level-1 and level-2 ad counts by category
x.category,
sum(ad_count) as num_ads
from
(
select -- count ads for level-1 categories, by category
a.id as category,
count(b.id) as ad_count
from
categories a
left outer join
ads b
on a.id = b.cat_id
where
a.tree = 0
group by
a.id
union
select -- count ads for level-2 categories, by level-1 category
c.tree as category,
count(d.id) as ad_count
from
categories c
left outer join
ads d
on d.cat_id = c.id
where
c.tree <> 0
group by
c.tree
) x
group by
x.category
) y
left outer join
(
select -- count sub_categories by category
tree as category,
count(id) as sub_category_count
from
categories
where
tree <> 0
group by
tree
) z
on y.category = z.category
order by
category;
结果:
+----------+--------------------+---------+
| category | num_sub_categories | num_ads |
+----------+--------------------+---------+
| 1 | 1 | 0 |
| 2 | 0 | 1 |
| 6 | 3 | 2 |
+----------+--------------------+---------+
3 rows in set (0.00 sec)
如果您的层次结构超过2个级别,那么它将变得更加复杂。
答案 1 :(得分:0)
正如其他人所说,MySQL可能不是这项任务的最佳选择。无论如何,如果您想使用它,可以使用Nested set model找到解决方案。使用另外两个整数字段categories
和lb
扩展表rb
,该字段将保留特定类别的左右边界。该类别的所有子类别都需要将其间隔[lb, rb]
完全包含在父类别间隔内。因此,表categories
应如下所示:
id tree lb rb
==============
1 0 11 14
2 0 9 10
6 0 1 8
13 1 12 13
16 6 2 3
17 6 4 5
18 6 6 7
并返回您希望的结果的查询是:
select id,
(select count(*) from categories where lb >= cat.lb and rb <= cat.rb and tree > 0) as num_subcategories,
(select count(*) from ads a join categories c on a.cat_id = c.id where lb >= cat.lb and rb <= cat.rb) as num_ads
from categories cat
where tree = 0;
这是fiddle。请注意,类别的插入和删除会变得更加复杂,这是在整个层次结构中轻松搜索的权衡。以下是插入过程:
drop procedure if exists insert_category;
create procedure insert_category(_id int, _parent_id int)
begin
declare _parent_rb int default null;
if _parent_id = 0 then
set _parent_rb = 1;
else
select rb from categories where id = _parent_id
into _parent_rb;
end if;
update categories set rb = rb + 2 where rb >= _parent_rb;
update categories set lb = lb + 2 where lb >= _parent_rb;
insert into categories(id, tree, lb, rb)
values (_id, _parent_id, _parent_rb, _parent_rb + 1);
end;
要按上述方式填写表类别,只需多次调用此过程:
call insert_category(1, 0);
call insert_category(2, 0);
call insert_category(6, 0);
call insert_category(13, 1);
call insert_category(16, 6);
call insert_category(17, 6);
call insert_category(18, 6);
HTH。