Подсчет подкатегорий и рекламы в каждой подкатегории mysql

0

Как говорится в названии, у меня есть две таблицы по категориям и другие для рекламы

  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
    MySQL очень плохо поддерживает иерархические структуры данных (если вы используете 8+, пожалуйста, отметьте это). Хотя это может быть решено для данных, которые вы предоставляете, общее решение является более сложным.
  • 0
    Я использую MySQL 5.6.15.
Показать ещё 1 комментарий
Теги:

2 ответа

1
Лучший ответ

Если у вас есть только двухуровневая иерархия, вы можете сделать это следующим образом:

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 уровня, тогда она станет более сложной.

  • 0
    да, у меня есть только два уровня: кошки, подкадры и реклама. попробую ваш ответ, когда я приду домой. Благодарю. Я попробовал ваш ответ здесь sqlfiddle.com/#!9/31f249/2 и он работает.
  • 0
    Спасибо, Рон, я думаю, я пойду с твоим решением, так как я знаком с ним и проще. Большое спасибо, это работает как шарм в моем коде.
0

Как говорили другие, MySQL, вероятно, не лучший выбор для этой задачи. Если вы хотите использовать его в любом случае, это возможное решение с использованием модели Nested set. Расширение 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;

Вот скрипка. Обратите внимание, что вставки и удаления категорий будут усложняться, что является компромиссом для легкого поиска по всей иерархии. Вот процедура для вставки:

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);

НТН.

  • 0
    Привет, спасибо за ваш ответ, я пытаюсь понять, почему и как вы заполнили именно эти цифры в фунтах и рублях. почему именно 9 и 10 в первом ряду и так далее, выглядит интересно, но я должен вставить новые строки с новыми категориями.
  • 0
    @samirdaraf Я расположил их так, чтобы все подходили, учитывая, что категория 1 является родительской для 13, а 6 является родительской для 16, 17 и 18. Процедуры вставки и удаления немного сложны, вам необходимо увеличить / уменьшить существующие интервалы.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню