我们处理来自客户的例行数据馈送,该客户刚刚将其数据库从看起来熟悉的形式(每个实体一行,每个属性一列)重构为我不熟悉的形式(每个实体每个属性一行):
之前:每个属性一列
ID Ht_cm wt_kg Age_yr ...
1 190 82 43 ...
2 170 60 22 ...
3 205 90 51 ...
之后:所有属性的一列
ID Metric Value
1 Ht_cm 190
1 Wt_kg 82
1 Age_yr 43
1 ...
2 Ht_cm 170
2 Wt_kg 60
2 Age_yr 22
2 ...
3 Ht_cm 205
3 Wt_kg 90
3 Age_yr 51
3 ...
这个数据库结构有名字吗?相对优势是什么?旧方法似乎更容易对特定属性(非空、非负等)设置有效性约束,并且更容易计算平均值。但是我可以看到在不重构数据库的情况下添加新属性可能会更容易。这是结构化数据的标准/首选方式吗?
它被称为实体-属性-值(有时也称为“名称-值对”),当人们在关系数据库中使用 EAV 模式时,它是“方孔中的圆钉”的经典案例。
以下是您不应该使用 EAV 的原因列表:
SELECT height, weight, age FROM Client where height is null or weight is null
.相比:
至:
这是您应该使用 EAV 的时间的(非常短的)列表:
我知道我刚刚花了整篇文章详细说明了为什么在大多数情况下 EAV 是一个糟糕的主意——但在少数情况下它是必要的/不可避免的。然而,大多数时候(包括上面的例子),它会比它的价值要麻烦得多。如果您需要广泛支持 EAV 类型的数据输入,您应该考虑将它们存储在键值系统中,例如 Hadoop/HBase、CouchDB、MongoDB、Cassandra、BerkeleyDB。
实体属性值(EAV)
包括我在内的许多人都认为它是一种反模式。
以下是您的替代方案:
使用数据库表继承
使用 XML 数据和SQLXML 函数
使用 nosql 数据库,例如 HBase
在 PostgreSQL 中,处理 EAV 结构的一种非常好的方法是附加模块
hstore
,可用于 8.4 或更高版本。手册:需要额外的模块 hstore。看:
从 Postgres 9.2 开始,它也有
json
类型和许多功能(其中大部分是在 9.3 中添加的)。Postgres 9.4 增加了(很大程度上优越的)“二进制 JSON”数据类型
jsonb
。具有高级索引选项。有趣的是,EAV db 模型是如何受到批评甚至被某些人视为“反模式”的。
就我而言,主要缺点是:
但是,您绝对不应该放弃此解决方案,原因如下:
如果您有一个使用 EAV 结构的数据库,则可以通过多种方式查询数据。
@Simon 的回答已经展示了如何使用多个连接执行查询。
使用的样本数据:
如果您使用的是具有
PIVOT
功能的 RDBMS(SQL Server 2005+ / Oracle 11g+),那么您可以通过以下方式查询数据:请参阅带有演示的 SQL Fiddle
如果您无权访问
PIVOT
函数,则可以使用带有CASE
语句的聚合函数来返回数据:请参阅带有演示的 SQL Fiddle
这两个查询都将在结果中返回数据: