Добавьте столбец к категориям, который дает основную категорию, в которой находится каждая категория (с указанием основных категорий). Итак:
cat_id | main_cat_id | title
-------+-------------+---------
01 | 01 | Science
0101 | 01 | Medicine
02 | 02 | Sport
Выберите из этого списка cat_id = main_cat_id, чтобы найти основные категории; присоединитесь к себе на left.cat_id = right.main_cat_id, чтобы найти дочерние категории, затем к сообщениям на cat_id = cat_id. Сгруппировать по left.cat_id и спроецировать на cat_id и count (*).
Я пробовал это в PostgreSQL 8.4, и я не понимаю, почему это не сработает в MySQL, так как запрос довольно прост. Мои столы:
create table categories(
cat_id varchar(40) primary key,
main_cat_id varchar(40) not null references categories,
title varchar(40) not null
)
create table posts (
post_id integer primary key,
cat_id varchar(40) not null references categories,
title varchar(40) not null
)
Мой запрос (группировка по названию, а не по идентификатору):
select m.title, count(*)
from categories m, categories c, posts p
where m.cat_id = c.main_cat_id
and c.cat_id = p.cat_id
group by m.title
ОБНОВЛЕНИЕ: я также попытался выполнить эту работу с помощью строковой операции, как пытался ОП. Запрос (в стандартном SQL, принятом PostgreSQL, а не на диалекте MySQL):
select m.title, count(*)
from categories m, posts p
where m.cat_id = substring(p.cat_id from 1 for 2)
group by m.title;
Который работает нормально. Я не могу предложить значимого сравнения по скорости, но план запроса для этого выглядел немного проще, чем для двустороннего соединения.