我正在尝试实现一个具有多值属性的数据库,并创建一个基于过滤器的搜索。例如,我希望我的people_table包含id,姓名,地址,爱好,兴趣(爱好和兴趣是多值的)。用户将能够检查许多属性,而sql将仅返回拥有所有属性的人。
我完成了学习,并找到了实现这一目标的一些方法,但我无法确定哪一个是最好的。
所以我的问题是:我可以使用第三种实现方式,还是有一个很大的缺点,我无法获得?还有你建议我使用前两种方法中的哪一种?
答案 0 :(得分:4)
这是典型的 n到m关系。它像这样工作
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'
答案 1 :(得分: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 support和JSON 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不支持的类型约束。