幾乎在所有web項目中,都涉及文章分類和標簽的設計,應該說這是一個比較常見、典型的案例。站長並不保證我的思路就是最好的,只是分享出來大家一起交流一下,互相促進與提高。
我們假設的開發項目是一個博客系統,最核心的部分就是與文章相關的,那么我們今天討論如何設計博客系統的文章分類和標簽。
1、首先,分類和標簽都是要和具體的文章相關聯的,當然也可能一些文章既沒有分類也沒有標簽,這一點是大家在寫查詢的時候容易疏忽的地方。因為我們的第一感覺就是,在查詢文章列表的時候關聯分類表,查出所有的文章和分類,對應關系一般是文章表的分類id對應分類表的id,使用where子句進行限定。這里就存在一個問題了,由於使用了where子句,那么只能查詢有分類的文章,而沒有分類的文章就查詢不到了。這時候怎么辦?應該使用連接查詢,left join,這要沒有分類的文章,在文章分類id那一欄會顯示null。通常我們只使用left join,而很少使用right join。
2、一般,一篇文章最好只對應一個分類,當然如果你想要對應多個分類也可以。但站長並不提倡,文章在多個分類中重復會給人很不專業的感覺,即使有些文章可能確實設計到多方面的內容,那么你應就其中的側重點來分類。而標簽就不一樣了,一篇文章可能有多個標簽。這就意味着我們無法靠一個sql語句既查出所有文章的分類和標簽,又做到查詢結果中的文章id不重復。通常我們需要把查詢出來的結果直接循環出來,那么這個結果一般是二維數組,第二維的都存儲了唯一一篇文章的相關信息。但是,標簽和文章是多對一的關系,多個標簽對應一篇文章,如果你只用一條sql語句的話,那么我們查詢出來的結果,當然也是多行,這不符合我們目標數據的要求。應此,需要在查詢完文章和分類之后,在前面結果的基礎上再查詢一次文章標簽,把兩次的結果結合起來,存在數組中,這是對應文章列表頁面的查詢方法。對於具體文章頁面,可以分兩次查詢。
好了,還沒有給出具體的數據庫設計,就先說了如何查詢結果,相信大家也看煩了,下面就舉例說明:
一、文章表:post,字段如下:
id【唯一標識】,aid【作者id】,title【標題】,content【內容】,cid【分類id】
二、分類表,category,字段如下:
id【唯一標識,與post表的cid關聯】,name【分類名】
三、標簽表,tag,字段如下:
id【唯一標識】,name【標簽名】
四、標簽與文章對應關系表,tag_relationship,字段如下:
id【唯一標識】,postid【文章id,與post表的id關聯】,tagid【標簽id,tag表的id關聯】
有朋友可能會問:為什么要單獨用一個表來存儲文章與標簽的對應關系,為什么不可以直接在tag表中增加一個文章id字段呢,比如:
tag表:
id,postid,name
這樣做的話,並不是不可以,但是,由於一篇文章對應多個標簽,所以name字段的值會出現很多重復,比如一篇文章,假設文章id為1,有2個標簽,php和mysql,那么在tag表會這樣存儲:
id:1,postid:1,name:php
id2,postid:1,name:mysql
另一篇文章,假設id為2,有2個標簽,也是php和mysql,那么在tag表中它會這樣存儲:
id:3,postid:2,name:php
id4,postid:2,name:mysql
大家很快就發現了問題,這樣的設計name字段也就是標簽的名稱在同一張表中可能會大量重復。但是這樣設計的好處是,如果你要查詢一個標簽下有多少篇文章,只要單獨查這個表就可以了,比如要查詢含有php標簽的文章有多少篇,只需要select count(name) from tag where name=’php’,就可以查出來。不好的地方是,如果要查詢所有標簽的集合,使用這種設計需要使用group by name語句來去除重復的行。如果用之前的那種,只需要select * from tag就可以了。一時之間,好像不太好取舍。這兩種設計都會有數據冢余,第一種tag_relationship表中,存在tagid字段的重復;而這兩種設計又都有各自的好處。那么我們到底該怎么選擇呢?站長也說不好,所以無法為大家下結論。但是站長在研究wordpress數據結構的時候,發現wp是采用的單獨建表存儲文章與標簽對應關系的方式。
另外,如何設計有時候也是取決具體功能的需求的,所以這個問題就留給大家一起來討論吧~