在多对多关系中选择特定属性

时间:2019-12-03 15:35:27

标签: mysql sql

考虑我有这种情况:

users

| id | name |
|----|------|
| 1  | Joe  |

attributes

| id | name   |
|----|--------|
| 1  | Age    |
| 2  | Height |
| 3  | Gender |

client_attribute

| id | client_id | attribute_id | value |
|----|-----------|--------------|-------|
| 1  | 1         | 1            | 45    |

属性可以扩展到数百个变体。查询用户并选择“常见”属性列时,例如“年龄”:

我的代码应该采用属性的名称还是ID?如果不是,是否应将通常访问的属性直接放在users表上?如果这些通用属性继续扩展该怎么办?

我的查询可能会选择不同区域中的两个或三个属性,我发现此表设计使事情变得困难(但我可以看到它的参数)。

3 个答案:

答案 0 :(得分:1)

给出的说明实际上并不是实体之间的“多对多”关系。

显示的表是典型的EAV(实体-属性-值)实现的说明。

问:我的代码应采用属性的name还是id

A:通常,SQL将按attribute引用id行。但是我们也可以使用name列。通常,应用程序代码将处理“选定”属性的转换。 (我们将需要研究一些示例进行说明。)

问:如果不是,是否应将常用属性直接放在用户表上?

A:传统的关系模型在实体上只有一行(例如user表中的一行),每个属性都有单独的一列:名字,姓氏,性别,出生日期,高度等

问:如果这些通用属性继续扩展该怎么办?

在传统的关系模型中,我们将添加其他列(DDL ALTER TABLE操作。对于EAV模型,我们不需要添加列,我们将向attribute表中添加行(DML INSERT操作)。

EAV模型更为复杂,因为属性值不存储在实体行中,而是作为单独表中的行存储,就像我们对多值属性的存储一样。您注意到,EAV既有优点,也有明显的缺点。


问:我的查询可能会选择不同区域的两个或三个属性,而我发现这种表设计会使事情变得困难

A:真正的复杂性(和性能问题)是在试图纠缠EAV模型以返回行的时候出现的,就像我们回到传统的关系模型中一样;如果我们尝试编写一个查询,该查询返回的行看起来像是来自user表的行,并且每个属性都有单独的列。

如果我们进行EAV,那么我们应该进行完整的EAV,而不是尝试编写返回结果集看起来像来自关系模型的SQL的SQL。可能,但是查询变得复杂。


此外,我不会存储“ age”属性,因为该属性会随时间而变化;一个人的年龄是当前日期和出生日期之间的差。

对于初学者来说,EAV模型具有很大的灵活性和易用性。这种灵活性是有代价的。考虑如何处理属性的各个域。名字和姓氏字符串可以存储为VARCHAR,但是某些属性可以是日期,十进制,整数。我们是将所有属性存储为VARCHAR,还是应该有多个列,然后使用某种区分符告诉我们应从中提取该属性的数据类型列。

答案 1 :(得分:0)

您可以使用复选框来选择“属性”,其值将是ID,在查询中,您将使用“ WHERE attributes in ("$variable") $ variable将包含您要选择的所有ID。

答案 2 :(得分:0)

  

我的代码应该采用属性的名称还是id?

最好对联接和名称使用PK /索引,但基本上两者都可以工作,只是对性能的影响很小。

  

如果没有,应该将常用属性放置在用户身上   桌子直接?如果这些通用属性继续扩展该怎么办?

在检索所需数据的任何子集时,我没有发现您提供的设计有任何问题或出现任何复杂问题。

1)检索所有用户和属性信息:

SELECT A.name, C.name, B.value FROM users A
JOIN client_attribute B ON A.id = B.client_id
JOIN attributes C ON B.attribute_id = C.id

输出:

Joe         Age     45
Joe         Height  5
Joe         Gender  Male
Michelle    Age     23
Michelle    Height  4
Michelle    Gender  Female

2)检索特定属性ex。年龄:

SELECT A.name, C.name, B.value FROM users A
JOIN client_attribute B ON A.id = B.client_id
JOIN attributes C ON B.attribute_id = C.id
where C.name = 'Age';

最好使用id:

SELECT A.name, C.name, B.value FROM users A
JOIN client_attribute B ON A.id = B.client_id
JOIN attributes C ON B.attribute_id = C.id
where C.id = 1;

输出:

Joe         Age   45
Michelle    Age   23

3)检索特定用户的信息:

SELECT A.name, C.name, B.value FROM users A
JOIN client_attribute B ON A.id = B.client_id
JOIN attributes C ON B.attribute_id = C.id
where C.id = 1 AND A.name = 'Joe';

或使用ID:

SELECT A.name, C.name, B.value FROM users A
JOIN client_attribute B ON A.id = B.client_id
JOIN attributes C ON B.attribute_id = C.id
where C.id = 1 AND A.id = 1;

输出:

Joe   Age   45
  

我的查询可能会选择不同区域中的两个或三个属性,   我发现此表设计使事情变得困难(但我可以看到   的参数)。

不太确定查询的意思是可以在不同区域中选择两个或三个属性,基本上可以编写查询以根据需要指定任何目标数据子集。希望以上内容能对您有所帮助,如果我错过了让我知道的事情。