我已经搜索了这个,并试图在过去几天自己做,但我不能。我在搜索范围内得到的最接近的是这个答案,也是堆栈溢出:EAV Select query from spreaded value tables如何查询实体属性值(EAV)模型中实体的所有信息?
所以我在这里,把自己变成了互联网!
因此,我有一个使用EAV(Entity-Attribute-Value)模型的数据库。但是这里有一个问题:实际的实体并不直接连接到其他EAV表。让我更具体一点;说有一个Person和一个Site表,并且他们只有他们的主键:person_id
和site_id
,分别。
因为这些实体(即人和站点)的属性(在我的模式中称为“属性”)必须是动态的,它们必须全部存储在它们各自的表(即EAV表)之外。以下是数据库模式的EAV部分(我不确定它是否完全正确,因此如果您有任何建议,请告诉我)。 - http://i.stack.imgur.com/EN3dy.png
架构的EAV部分主要有以下表格:
property
property_value_varchar
property_value_text
property_value_number
property_value_boolean
property_value_datetime
entity_tables
好了,所以,由于实体不是“直接连接”到EAV部分,我使用的entity_tables
表一样,以实际的表的引用,因此,与上面的例子中,entity_tables
表应该是这个样子:
--------------------------------------- |entity_table_id | entity_table_name | | 1 | person | | 2 | site | | . | . | | . | . | ---------------------------------------
的property
表是实际持有任何实体都可以持有,说“PERSON_FIRST_NAME”或“LOCATION_NAME”,或其他任何性质不同的一个。
property_value_*
表格除property_value
的数据类型外都完全相同。这些是保存每个实体对象属性的实际值的映射,它们由entity_table_id
和entity_object_id
映射。
让我给你的数据库的一个可能的情况下,为了清楚:
Person table ------------- | person_id | | 1 | | 2 | ------------- Site table ----------- | site_id | | 1 | | 2 | ----------- entity_tables table --------------------------------------- |entity_table_id | entity_table_name | | 1 | person | | 2 | site | --------------------------------------- property table ------------------------------------- | property_id | property_code | | 1 | PERSON_FIRST_NAME | | 2 | PERSON_LAST_NAME | | 3 | PERSON_BIRTH_DATE | | 4 | SITE_NAME | | 5 | SITE_PHONE_NR_1 | | 6 | SITE_PHONE_NR_2 | | 7 | SITE_LATITUDE | | 8 | SITE_LONGITUDE | | 9 | SITE_CITY | | 10 | SITE_COUNTRY | | 11 | SITE_ZIP_CODE | ------------------------------------- property_value_varchar table ----------------------------------------------------------------------------------------- | property_value_id | property_id | entity_table_id | entity_object_id | property_value | | 1 | 1 | 1 | 1 | Richard | | 2 | 2 | 1 | 1 | Hammer | | 3 | 1 | 1 | 2 | Bruce | | 4 | 2 | 1 | 2 | Heaton | | 5 | 4 | 2 | 1 | BatCave | | 6 | 5 | 2 | 1 | +49123456789 | | 7 | 4 | 2 | 2 | BigCompany | | 8 | 5 | 2 | 2 | 987654321 | | 9 | 6 | 2 | 2 | 147852369 | | 10 | 9 | 2 | 2 | Berlin | | 11 | 10 | 2 | 2 | Germany | | 12 | 11 | 2 | 2 | 14167 | ----------------------------------------------------------------------------------------- property_value_datetime table ----------------------------------------------------------------------------------------- | property_value_id | property_id | entity_table_id | entity_object_id | property_value | | 1 | 3 | 1 | 1 | 1985-05-31 | ----------------------------------------------------------------------------------------- property_value_number table ----------------------------------------------------------------------------------------- | property_value_id | property_id | entity_table_id | entity_object_id | property_value | | 1 | 7 | 2 | 1 | 1.402636 | | 2 | 8 | 2 | 1 | 7.273922 | ----------------------------------------------------------------------------------------- (property_value_text and property_value_boolean tables are empty)
正如你可以看到,不是每个实体的所有对象都具有一定相同属性(属性)。这个领域真的很宽松。
因此,现在像我之前的很多人一样,我不确定如何以可读的方式检索所有这些信息,即如何获取有关人员表或记录的所有信息地点表?
也就是说,我怎么能得到这样的:
Person table view ---------------------------------------------------- | Person ID | Property code | Property value | | 1 | PERSON_FIRST_NAME | Richard | | 1 | PERSON_LAST_NAME | Hammer | | 1 | PERSON_BIRTH_DATE | 1985-05-31 | | 2 | PERSON_FIRST_NAME | Bruce | | 2 | PERSON_LAST_NAME | Heaton | ---------------------------------------------------- Site table view ------------------------------------------------ | Site ID | Property code | Property value | | 1 | SITE_NAME | Batcave | | 1 | SITE_PHONE_NR_1 | +49123456789 | | 1 | SITE_LATITUDE | 1.402636 | | 1 | SITE_LONGITUDE | 7.273922 | | 2 | SITE_NAME | BigCompany | | 2 | SITE_PHONE_NR_1 | 987654321 | | 2 | SITE_PHONE_NR_2 | 147852369 | | 2 | SITE_CITY | Berlin | | 2 | SITE_COUNTRY | Germany | | 2 | SITE_ZIP_CODE | 14167 | ------------------------------------------------
也不像这个,如果是比较容易:
Person table view ------------------------------------------------------------------------ | Person ID | PERSON_FIRST_NAME | PERSON_LAST_NAME | PERSON_BIRTH_DATE | | 1 | Richard | Hammer | 1985-05-31 | | 2 | Bruce | Heaton | | ------------------------------------------------------------------------ Site table view ---------------------------------------------------------------------------------------------------------------------------------------- | Site ID | SITE_NAME | SITE_PHONE_NR_1 | SITE_PHONE_NR_2 | SITE_LATITUDE | SITE_LONGITUDE | SITE_CITY | SITE_COUNTRY | SITE_ZIP_CODE | | 1 | Batcave | +49123456789 | | 1.402636 | 7.273922 | | | | | 2 | BigCompany | 987654321 | 147852369 | | | Berlin | Germany | 14167 | ----------------------------------------------------------------------------------------------------------------------------------------
我意识到这可能会相当混乱。请让我知道我还能如何帮助您,例如获取更多信息或更好地解释某些部分。
我也不期望1个SQL查询(每个实体)来做这个把戏。我意识到可能有超过1个查询,并且它/他们很可能需要由PHP(例如)“组合”,以便真正实现动态化。所以,即使有人甚至可以解释我如何才能获得所有这些信息,只是为了我上面的假设属性(属性),我已经非常感激!
谢谢你的帮助!
不幸的是,EAV通常是反模式。它使得你想要的各种查询非常繁琐 - 你必须将许多你认真避免的“硬编码”的东西“硬编码”到一个模式中,从而失去任何好处。特别是,'SELECT'查询列的* type *不能依赖于表的*内容* - 它必须在查询时已知,或者可以从表列或表达式的* type *中发现,所以只有这样才能编写一个能够产生像第一个例子那样的输出的查询,就是加入* every *'result_value _...'表并合并... –
...将结果合并到具有'COALESCE()的单个字段中'或类似的。但是,那么这个列的类型必然会变成一些最小公因分母类型(可能是无界的'VARCHAR'),所以你不能对它们执行最明智的操作(例如,即使你不能为每个值添加5知道它们最初是数字的,没有先显式转换为数字类型)。一些RDBMS(可能MySQL,我不知道)有“pivoting”扩展,可能允许行按照你以后的代码片段转换成列,但这是TTBOMK而不是标准的SQL。 –
如果您首先使用EAV来允许用户编写高度可定制的查询,那么我的建议是以通常的方式重新设计您的数据库模式(即使用一组固定编码的列),并通过以下方式为用户提供查询灵活性:允许他们从通过其特殊元数据系统表(所有数据库提供此信息,例如通过“INFORMATION_SCHEMA”提供)中从数据库中提取的列表中选择字段,表等,然后从中创建一个定制的“SELECT”命令。 –