2012-03-03 131 views
1

讓我們拿SO網站。它有問題和問題有它的標籤。我的問題是,什麼是顯示問題及其標籤的最佳方式。假設他們在不同的表格中。你可以使用SELECT JOIN查詢問題及其標籤嗎?

SELECT * FROM questions RIGHT JOIN tags ON questions.id = tags.question_id

但也有不止一個標籤,所以我們怎麼會一起顯示出來?或者我們只需要做2 SELECTs?因爲如果是的話,那麼它會花費很多資源,因爲我們在一個頁面中顯示多個問題。

+0

您的標籤表是您的問題表和標籤表之間的多對多嗎? – nnichols 2012-03-03 21:16:14

回答

1

首先SO至少需要一個標記,以便不需要right join,它實際上應該是一個left outer join,如果你想要做什麼,我覺得你這樣做......

正如你所說,可以有更多而不是一個標籤,這表明我們需要orin或返回多個行或進行某種類型的字符串聚合。

但是,這不會是一個非常好的數據模型,因爲您仍然需要知道該問題的標籤。所以,最好的辦法是將標籤存儲在posts表格中,而不用擔心tag_id混亂。

這實際上是這樣做的。

您的查詢(實際上工作)然後是:

select Tags 
    from Posts 
where Id = ? 

Tagsnvarchar(150),這對於問題的標籤的分隔列表,在你看到他們對你的問題,如果相同的格式這很有趣!

無論何時輸入新標籤,它都會自動創建標籤,並使用同義詞來確保人們的錯誤拼寫得到糾正。所以,有一個TagsId | TagName和一個TagSynonoyms表,(我不知道維基總結保存在哪裏)。然後,您可以在寫入Posts表之前分配標籤檢查以查看它是否有同義詞並進行更正。

雖則回答你的問題,查詢會(也實際工作):

select p.*, t.TagName 
    from Posts p 
    join PostTags pt 
    on p.Id = pt.PostId 
    join Tags t 
    on pt.TagId = t.Id 

我不認爲這是什麼,所以實際上沒有 - 我甚至不知道爲什麼會出現一個PostTagsTags表,因爲任何標記都是允許的,不需要執行外鍵查找來檢查標記是否存在。而且沒有必要以這種規範化的方式存儲關係。您只需要Posts列中的Tags列和TagSynonyms表以確保同義詞系統正常工作。然後,如果主鍵不是Id而是TagName,則只需要查找一次。

4

假設tags表中有一個name列,我會用GROUP_CONCAT函數。

SELECT questions.*, 
     GROUP_CONCAT(DISTINCT tags.name -> ORDER BY tags.id SEPARATOR ',') AS `tag_names`, 
     GROUP_CONCAT(DISTINCT tags.id -> ORDER BY tags.id SEPARATOR ',') AS `tag_ids` 
FROM questions 
     RIGHT JOIN tags 
     ON questions.id = tags.question_id 

這將顯示2柱tag_namestag_ids其中值將是逗號分隔。當我們獲取值時,我們可以將其分解並獲得真實值。

while($row=mysql_fetch_assoc($result)){ 
     $tag_names = explode("," $row['tag_names']; 
     $tag_ids = explode("," $row['tag_ids']; 
     $tags = array_combine($tag_ids, $tag_names); 
    } 

現在$tags成爲一個關聯數組,其關鍵字是標記ID,值是標記名稱。

如果使用下面的表達式,它會創建一個JSON。但不依賴於它,如果你的標籤名稱有哪些需要轉義的任何字符(例如"

Concat('{', GROUP_CONCAT(Concat('"', tags.id, '":"', tags.name, '"') 
       ORDER BY 
       tags.id), '}') AS `tag_o` 

通過$tags = json_decode($row['tag_o']);

0

的獲取JSON對象下一個給你一個具體問題的所有標籤。

SELECT * FROM `questions` q INNER JOIN `tags` t ON q.id = t.question_id; 
0

這假定您的標籤表是標籤和問題之間的多對多。

SELECT questions.*, GROUP_CONCAT(CONCAT(tag.id, '::', tag.name)) 
FROM questions 
LEFT JOIN tags 
    ON questions.id = tags.question_id 
LEFT JOIN tag 
    ON tags.tag_id = tag.id 
GROUP BY questions.id