Mysql 如何进行此eav查询以生成水平结果

Mysql 如何进行此eav查询以生成水平结果,mysql,sql,entity-attribute-value,Mysql,Sql,Entity Attribute Value,本案: 表: product: product_id|name | ------------------------ 1 |iphone 4 | 2 |gallaxy 2 | 3 |blackbery 6 | product_attribute: id|product_id|attribute_id -------------------------------------------------- 1 |1

本案:

表:

product:
product_id|name        |
------------------------
1         |iphone 4    |
2         |gallaxy 2   |
3         |blackbery 6 |

product_attribute:

id|product_id|attribute_id
--------------------------------------------------
 1 |1        |2
 2 |1        |6
 .    .        .

attribute:
------------------------------
attribute_id|name  |value|
        1   |width |300
        2   |width |320
        3   |width |310
        4   |height|390
        5   |height|370
        6   |height|380
应得到以下结果:

product_id|height|width
 1        |380   |320
 ......................
编辑: 高度和宽度属性是产品属性中唯一的一部分——产品需要具有动态能力,以便用户在后端添加,就像在magento中一样,因为我选择了eav db设计。 如果可能的话,请写下疑问,以防我们不知道产品的名称


谢谢

有几种方法可以实现这一点。对于每个属性值,类似这样的操作应该可以在表上多次连接:

SELECT p.product_id,
    a.value height,
    a2.value width
FROM Product p
    JOIN Product_Attribute pa ON p.product_id = pa.product_id 
    JOIN Attribute a ON pa.attribute_id = a.attribute_id AND a.name = 'height'
    JOIN Product_Attribute pa2 ON p.product_id = pa2.product_id 
    JOIN Attribute a2 ON pa2.attribute_id = a2.attribute_id AND a2.name = 'width'
这是我的答案

以下是我个人更喜欢的另一种使用MAX和GROUP BY的方法:

SELECT p.product_id,
    MAX(Case WHEN a.name = 'height' THEN a.value END) height,
    MAX(Case WHEN a.name = 'width' THEN a.value END) width
FROM Product p
    JOIN Product_Attribute pa ON p.product_id = pa.product_id 
    JOIN Attribute a ON pa.attribute_id = a.attribute_id 
GROUP BY p.product_id

祝你好运。

一种方法是在选择列表中使用相关子查询,尽管这对于大型集合的性能可能不是最佳的。对于只从product表中检索几行来说,这并不坏。(您肯定需要适当的索引。)


此查询将返回product中的行以及属性值(如果存在)。如果未找到属性值,查询将返回一个NULL来代替属性值。(这与使用内部联接代替相关子查询的查询行为不同……在这种情况下,属性表或product_属性表中的“缺失”行将从返回的产品中过滤掉该行。)

LIMIT子句的目的是保证子查询返回的行不超过一行。(如果SELECT列表中的子查询返回多行,MySQL将返回错误。)ORDER BY的目的是在多行满足子查询的情况下使查询具有确定性。(如果没有ORDERBY子句,当有多行时,MySQL可以任意返回它选择返回的任何一行。)

对于“多值”属性,同样的方法也适用。我们只是添加了更多的子查询,但是指定LIMIT 1,1来返回第二个属性值,LIMIT 2,1来返回第三个值,等等


(哦,在关系数据库中实现EAV模型的乐趣。)


后续行动: 问:“……更一般的情况是,在eav db中,我们不知道之前有哪些属性名。”

答:关系模型基于一个元组包含指定数量、指定类型的列的原则

您(显然)试图做的是在运行查询时返回可变数量的列。SELECT语句包括要返回的表达式的特定列表;这不能改变,并且每个表达式返回的值的数据类型不会因行而异

上面的查询为每个产品返回一个“高度”属性值实例和一个“宽度”属性值实例

对于更“一般”的情况,我们真的希望每个属性值在其各自的单独行上返回

如果您不知道“提前”与产品关联的属性,则更一般的查询是:

SELECT p.product_id
     , a.attribute_id
     , a.name         AS attribute_name
     , a.value        AS attribute_value
  FROM product p
  LEFT
  JOIN product_attribute q
    ON q.product_id = p.product_id
  LEFT
  JOIN attribute a
    ON a.attribute_id = q.attribute_id
 WHERE p.product_id = 1
 ORDER
    BY p.product_id
     , a.name
     , a.attribute_id
这将返回一个可以轻松处理的结果集:

product_id attribute_id attribute_name attribute_value
---------- ------------ -------------- ---------------
         1            6 height         380
         1            2 width          320
Q:“看起来应该分两个阶段完成:1.获取产品2的所有属性名称。然后在for循环中使用服务器端属性名称代码编写代码”

答:不,看起来单个查询将返回产品的所有属性名称和值对。每个属性名称/值将位于单独的行上

不需要使用“for循环”来生成针对数据库的附加查询。是的,这是可能的,但完全没有必要

如果您有一些奇怪的需求,需要编写另一个针对数据库运行的查询,以指定的格式返回resultset,那么无论您如何处理“更一般的情况”语句中的resultset,只处理resultset可能会更有效,不需要对数据库运行任何查询

如果需要返回如下所示的结果集:

 product_id height width
 ---------- ------ -----
          1 380    320
SELECT 1 AS product_id, '380' AS height, '320' AS width
(编写另一个查询的要求非常奇怪)完全可以使用“更一般的查询”中的结果集生成如下所示的查询:

 product_id height width
 ---------- ------ -----
          1 380    320
SELECT 1 AS product_id, '380' AS height, '320' AS width

虽然这样的练习是毫无意义的,因为您没有返回任何以前没有返回的新信息,现在您有另一个需要处理的结果集,在我看来,这只是一堆不必要的开销。

首先让我说这是一个非常糟糕的设计。在您当前的方法下,您将需要运行多个子查询或带有表别名的联接来获得您想要的结果

SELECT 
    product_id,
    (
        SELECT product_attribute.value 
        FROM product_attribute, attribute 
        WHERE product_attribute.product_id=product.product_id 
        AND product_attribute.attribute_id=attribute.attribute_id
        AND product_attribute.name = 'width'
    ) AS 'width',
    (
        SELECT product_attribute.value 
        FROM product_attribute, attribute 
        WHERE product_attribute.product_id=product.product_id 
        AND product_attribute.attribute_id=attribute.attribute_id
        AND product_attribute.name = 'height'
    ) AS 'height'
FROM
    product
ORDER BY 
    ...      
让我建议: 这样,您就有了一个确定的属性列表,以及每个产品的单个属性值

SELECT attribute_sid, value FROM product_attribute WHERE product_id = 1

。。。将检索所有属性和值,这些属性和值可以方便地放在下面已有的
dict
数组
、或
map

答案中。但除此之外,product_属性中的列id是多余的、毫无意义的,它的用途是什么?试图生成一个返回结果集(如图所示)的查询是完全没有意义的,也是一种资源浪费,这取决于要查询的表中可能存在或不存在的行。您将在数据库上造成大量不必要的处理。您最好返回一个“更一般的情况”结果集,每个属性名称/值对位于单独的行上,而不是尝试将这些行转换为列。下面答案中的查询将EAV模型的一部分展平为固定列……注意:对于使用内部联接的此查询返回的产品,该产品必须同时具有“高度”和“宽度”属性。属性和/或product_属性表中“缺少”一行的任何产品(例如没有“heig