Подсчет записей, относящихся к категории в MySQL - PullRequest
1 голос
/ 04 сентября 2010

Я боролся с каким-то SQL-кодом и, похоже, не могу обойти его.

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

То, что я пытаюсь сделать, - это найти, сколько статей представлено для каждой категории.

Вот SQL, который у меня есть до сих пор

SELECT DISTINCT COUNT( po.post_Cat_ID ) AS Occurances, ca.cat_Title
FROM Posts po, Categories ca
WHERE ca.cat_ID = LEFT( po.post_Cat_ID, 2 )

Причина, по которой я использую LEFT, заключается в том, чточтобы получить только основные категории, так как я перечислил категории следующим образом ... например,

Science = 01
Medicine = 0101
Sport = 02

В сообщениях, скажем, asprin, следовательно, будет cat_ID как 0101. (Затем LEFT обрежет 0101, 0102, 0103и т. д. до 01).В основном я не заинтересован в подкатегориях.

Заранее спасибо


Результат

SELECT DISTINCT COUNT( po.post_Cat_ID ) AS Occurances, ca.cat_Title
FROM Posts po, Categories ca
WHERE ca.cat_ID = LEFT( po.post_Cat_ID, 2 )
GROUP BY LEFT( po.post_Cat_ID, 2 )

ps спасибо @nullpointer, он работает длясейчас я перейду к реструктуризации для других читателей, вот ссылка снова

http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

Ответы [ 2 ]

0 голосов
/ 04 сентября 2010

Добавьте столбец к категориям, который дает основную категорию, в которой находится каждая категория (с указанием основных категорий). Итак:

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;

Который работает нормально. Я не могу предложить значимого сравнения по скорости, но план запроса для этого выглядел немного проще, чем для двустороннего соединения.

0 голосов
/ 04 сентября 2010

Позвольте мне предложить вам реструктурировать схему. Здесь вы хотите представить иерархическую структуру (категории), которая не совсем проста для реляционных баз данных. Два общих решения - это список смежности и вложенный набор.

Список смежности является более простой древовидной структурой. У вас будет таблица categories, например:

id  | name      | parent
------------------------
1   | Science   | null
2   | Sports    | null
3   | Medicine  | 1

К сожалению, с этой моделью сложно работать с использованием SQL. Вместо этого мы можем использовать подход с вложенными множествами. Здесь каждый узел имеет узел значений lft и rgt, который будет между значениями lft и rgt родителя. В вашем примере вы будете иметь:

id  | name      | lft  | rgt  
-------------------------------
1   | Science   | 1    | 4    
2   | Sports    | 5    | 6 
3   | Medicine  | 2    | 3

Таким образом, чтобы получить счет для определенной категории, вы можете просто запросить количество узлов, которые имеют значения lft и rgt между нужной категорией. Например:

   SELECT COUNT(*) 
     FROM articles a
LEFT JOIN categories c ON a.category_id = c.id
    WHERE lft BETWEEN 1 AND 4 
      AND rgt BETWEEN 1 AND 4

Предполагая, что ваша таблица article выглядит следующим образом:

id  | ... | category_id

Более подробно это обсуждается по адресу:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/


Я предложу другое решение: используйте теги, а не категории. Вы можете использовать несколько тегов для данной статьи и просто получить количество всех статей, соответствующих определенному тегу. С ним будет намного проще работать, а также вы получите гораздо больше гибкости.

Для этого вам понадобится отношение «многие ко многим» между статьями и тегами, которое обычно реализуется с помощью соединительной таблицы:

tags
id  | name

articles_tags # the junction table
article_id  | tag_id

Чтобы пометить статью, вы просто INSERT несколько записей в таблице articles_tags с правильными article_id и tag_id. Затем вы можете использовать JOIN s как обычно, чтобы получить то, что вы хотите.

...