计算属于MySQL中类别的记录

时间:2010-09-04 13:19:26

标签: mysql find-occurrences

我一直在与一些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 )

P.S。感谢@nullpointer,它目前有效,我会考虑重组 为其他读者再次提供链接

  

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

2 个答案:

答案 0 :(得分:0)

我建议您重新构建架构。你想要的是表示一个层次结构(类别),这对于关系数据库来说并不是那么简单。两种常见的解决方案是邻接列表和嵌套集。

邻接列表更像是一种简单的树状结构。您将拥有一个categories表格,如:

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

不幸的是,使用SQL很难处理这个模型。相反,我们可以嵌套集方法。此处每个节点都有lftrgt个值节点,它们位于父级lftrgt值之间。在您的示例中,您将拥有:

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

因此,为了检索特定类别的计数,您只需查询所需类别之间具有lftrgt值的节点数。例如:

   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_tagsarticle_id表中的tag_id表,其中包含正确的JOIN和{{1}}。然后你可以像往常一样使用{{1}}来获得你想要的东西。

答案 1 :(得分:0)

向“类别”添加一列,该列提供每个类别所在的主要类别(主要类别为自己)。所以:

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
)

我的查询(按标题而不是ID分组):

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

更新:我也尝试过使用字符串操作来完成这项工作。查询(在PostgreSQL接受的标准兼容SQL中,而不是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;

哪个工作正常。我无法对速度进行有意义的比较,但对此的查询计划确实看起来比双向连接更简单。