计算每个子类别mysql中的子类别和广告

时间:2018-01-20 20:51:33

标签: mysql sql

正如标题所说,我有两个表,一个用于分类,另一个用于广告

  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的位置(主要类别)。

这是my fiddle

2 个答案:

答案 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找到解决方案。使用另外两个整数字段categorieslb扩展表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。