2010-09-04 26 views
1

我一直在與一些SQL進行對抗,似乎無法擺脫困境。在MySQL中計算屬於某個類別的記錄

我有兩張表,一張帶有類別列表,另一張帶有我的所有文章。

我想要做的是找到每個類別有多少篇文章。

這裏是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) 

我用剩下的就是隻得到的主要類別爲我列出類別披露如下...例如

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) 

附:感謝@nullpointer,它的工作原理就目前而言,我會考慮重組 其他讀者繼承人的鏈接再次

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

+1

您是否嘗試過使用post_Cat_ID分組? – DrColossos 2010-09-04 13:40:56

+0

順便說一下,子類別的處理看起來相當複雜和低效... – DrColossos 2010-09-04 13:41:35

+0

是工作感謝 – Stevanicus 2010-09-04 14:17:07

回答

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多個條目進入帶有正確的article_idtag_idarticles_tags表。然後,您可以像往常一樣使用JOIN來得到您想要的。

+0

嵌套集合聰明和酷,但一個痛苦的工作。我建議OP確信他需要在改變任何事情之前給他的東西。 – 2010-09-04 13:54:27

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 

更新:我也有在做一個字符串操作這項工作了一槍,作爲OP嘗試。查詢(在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; 

哪個工作正常。我無法就速度提供有意義的比較,但查詢計劃看起來比雙向連接看起來簡單一些。

+0

這是我在我的答案中解釋的鄰接表方法的一種變體,當您擁有多個(子)類別的級別時,這會變得非常麻煩。 – NullUserException 2010-09-04 14:26:01

+0

@NullUserException:在某種程度上。如果您的數據庫可以執行遞歸查詢(Oracle,PostgreSQL,Firebird和SQL Server都可以 - 不確定MySQL),那麼它會變得稍微棘手,而不是非常麻煩,並且比嵌套更容易(並且AIUI更快)。但是由於OP沒有表現出對多個子類別的興趣,這似乎沒有意義。 – 2010-09-04 16:18:59