2017-02-14 53 views
0

我想實現一個具有多值屬性的數據庫並創建一個基於過濾器的搜索。例如,我希望我的people_table包含身份證,姓名,地址,興趣愛好(愛好和興趣是多值的)。用戶將能夠檢查許多屬性,而sql將只返回擁有全部屬性的人。用多值屬性實現數據庫的最佳方式是什麼?

我做了我的研究,我發現了一些方法來實現這一點,但我不能決定哪一個是最好的。

  1. 第一個是有一個人的基本信息表(id,名稱,地址),兩個多值屬性和另一個只包含其他表的關鍵字瞭解如何創建這個表格,我還不知道如何實現搜索)。
  2. 第二個是有一個表的基本信息,然後每個屬性一個。所以我會有20個或更多的桌子(足球,油漆,高爾夫,音樂,遠足等),他們只包含人的ID。然後,當用戶檢查業餘愛好和活動時,我將使用JOIN功能獲得期望的結果(我不確定複雜性,所以我不知道如果用戶做得多快許多檢查)。
  3. 最後一個是我沒有在互聯網上找到的實現(我知道有一個原因:)),但在我的腦海中是最容易實現,並在複雜性方面最快。只使用一個表格,它具有普通的基本信息,並且所有屬性都是布爾變量。所以,如果我在我的桌子上有1000人,那麼只會有1000個循環,而我認爲使用AND條件會變得足夠快。

所以我的問題是:我可以使用第三次執行還是有一個很大的缺點,我不明白?你建議我使用前兩種方法中的哪一種?

+0

你跟蹤這些愛好多少細節? – Schwern

+0

選項2聽起來非常可怕,選項3聽起來不好並且不規範。第一種選擇是IMO的方式,您可以查看下面的@Juergen答案以獲取更多信息。 –

+0

謝謝大家的快速回復。 @Schewrn我需要大約50個愛好和興趣(只是名字)。 –

回答

4

這是一個典型的n關係。它的工作原理是這樣的

persons table 
------------ 
id 
name 
address 

interests table 
--------------- 
id 
name 

person_interests table 
---------------------- 
person_id 
interest_id 

person_interests包含一個人的每個興趣的記錄。爲了得到一個人的利益做:

select i.name 
from interests i 
join person_interests pi on pi.interest_id = i.id 
join persons p on pi.person_id = p.id 
where p.name = 'peter' 

您可以爲hobbies還創建表格。爲了讓業餘愛好在單獨的查詢中做同樣的事情。要在一個查詢中得到兩個結果,你可以這樣做:

select p.id, p.name, 
     i.name as interest, 
     h.name as hobby 
from persons p  
left join person_interests pi on pi.person_id = p.id 
left join interests i on pi.interest_id = i.id 
left join person_hobbies ph on ph.person_id = p.id 
left join hobbies h on ph.hobby_id = h.id 
where p.name = 'peter' 
+0

我是否也可以爲業餘愛好創建表格,然後我無法使用JOIN功能? –

+0

@BroCode我會問自己,「嗜好」和「興趣」之間是否真的存在差異。 – Schwern

+0

@BroCode:是的,當然你也可以創建一個「嗜好」表。 –

0

處理這個問題的基本方法是使用多對多連接表。每個用戶可以有很多愛好。每個愛好都可以有很多用戶。這是基本的東西,你可以找到任何地方的信息,並@juergend already covered that

更難的部分是跟蹤關於各種愛好和興趣的不同信息。就像他們的愛好是「棒球」一樣,你可能想跟蹤他們的位置,但如果他們的愛好是「旅行」,你可能想跟蹤他們最喜歡的國家。用典型的SQL關係做這件事會導致表和列的快速擴散。

混合方法是使用新的JSON data type來存儲一些非結構化數據。要擴展@ juergend的例子,你可以在Person_Interests中添加一個字段,這個字段可以存儲一些關於這個人的興趣的細節。

create table Person_Interests (
    InterestID integer references Interests(ID), 
    PersonID integer references Persons(ID), 
    Details JSON 
); 

現在你可以補充說,45號人有興趣12(旅行),他們最喜歡的國家是吉布提,他們去過45個國家。

insert into person_interests 
    (InterestID, PersonID, Details) 
    (12, 45, '{"favorite_country": "Djibouti", "countries_visited": 45}'); 

你也可以使用JSON的搜索功能找到,例如,每個人她最喜歡的國家是吉布提。

select p.id, p.name 
from person_interests pi 
join persons p on p.id = pi.personid 
where pi.details->"$.favorite_country" = "Djibouti" 

這裏的優點是靈活性:興趣及其屬性不受數據庫架構的限制。

缺點是性能。 JSON數據類型不是最有效的,並且indexing a JSON column in MySQL is complicated。良好的索引對於良好的SQL性能至關重要。因此,當您找出常見模式時,您可能希望將常用屬性轉換爲真實表格中的實際列。


另一種選擇是使用table inheritance。這是Postgres的一個特性,而不是MySQL,我建議考慮切換。 Postgres也有better and more mature JSON supportJSON columns are easier to index

使用表繼承,而不必爲每個不同的興趣編寫一個全新的表,您可以製作從更通用的表繼承的特定表。

create table person_interests_travel (
    FavoriteCountry text, 
    CountriesVisited text[] 
) inherits(person_interests); 

這仍然有InterestID,是PersonID,和詳細信息,但它增加了一些特定的列來跟蹤自己喜歡的國家,他們訪問過的國家。

請注意,text[]Postgresql also supports arrays因此您可以存儲實際列表而無需創建另一個連接表。你也可以在MySQL中使用JSON字段來做到這一點,但是數組提供JSON不支持的類型約束。

相關問題