案例:
表:
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 design。 如果我们不知道产品的名称,请写下查询。
由于
答案 0 :(得分:5)
有几种方法可以实现这一点。对于每个属性值,这样的事情应该多次连接在表上:
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'
这是Fiddle。
以下是使用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
祝你好运。
答案 1 :(得分:3)
一种方法是在SELECT列表中使用相关子查询,尽管这可能不是大型集上性能的最佳值。要从产品表中检索几行行,它不会很糟糕。 (你肯定想要合适的索引。)
SELECT p.product_id
, ( SELECT a1.value
FROM attribute a1
JOIN product_attribute q1
ON q1.attribute_id = a1.attribute_id
WHERE q1.product_id = p.product_id
AND a1.attribute_name = 'height'
ORDER BY a1.id
LIMIT 0,1
) AS height_1
, ( SELECT a2.value
FROM attribute a2
JOIN product_attribute q2
ON q2.attribute_id = a2.attribute_id
WHERE q2.product_id = p.product_id
AND a2.attribute_name = 'width'
ORDER BY a2.id
LIMIT 0,1
) AS width_1
FROM product p
WHERE p.product_id = 1
此查询将返回product中的行以及属性的值(如果存在)。如果未找到属性值,则查询将返回NULL以代替属性值。 (这与使用INNER JOIN代替相关子查询的查询的行为不同...其中属性或product_attribute表中的“缺失”行将过滤掉返回的产品中的行。)
LIMIT子句的目的是保证子查询返回不返回多行。 (如果SELECT列表中的子查询返回多行,MySQL将返回错误。)ORDER BY的目的是使查询具有确定性,如果有多行满足子查询的话。 (如果没有ORDER BY子句,当有多行时,MySQL可以随意返回它选择的行。)
对于“多值”属性,同样的方法也适用。我们只需添加更多子查询,但指定LIMIT 1,1以返回第二个属性值,LIMIT 2,1以返回第三个值,等等。
(哦,关系数据库中实现的EAV模型的乐趣。)
问:“...更常见的情况,因为它发生在我们之前不知道属性名称的eav db中。”
A:关系模型基于元组包含指定类型的指定数量的列的原则。
您(显然)尝试做的是在运行查询时返回可变数量的列。 SELECT语句包括要返回的特定表达式列表;这不能改变,每个表达式返回的值的数据类型不会因行而异。
上面的查询为每个产品返回一个“height”属性值的实例,以及一个“width”属性值的实例。
对于更“更一般的情况”,我们真的希望每个属性值都在它自己的单独行上返回。
更一般的查询,如果您不“提前”知道与产品相关联的属性将是:
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
问:“看起来应该分两个阶段完成:1。获取产品的所有属性名称2.然后使用for循环中属性名称的服务器端代码编写代码”
答:不,看起来单个查询将返回产品的所有属性名称和值对。每个属性名称/值都在一个单独的行上。
无需使用“for循环”来针对数据库生成其他查询。是的,可以这样做,但完全没必要。
如果您有一些奇怪的要求,要构建另一个查询来针对数据库运行以返回您指定格式的结果集,那么无论您处理来自“更一般情况”语句的结果集的任何处理,它都可能是更有效地处理结果集,而不再对数据库运行任何查询。
如果需要返回如下所示的结果集:
product_id height width
---------- ------ -----
1 380 320
(如同组成另一个查询一样奇怪),完全有可能使用“更一般的查询”中的结果集来生成如下所示的查询:
SELECT 1 AS product_id, '380' AS height, '320' AS width
虽然这样的练习是毫无意义的,但鉴于你没有返回任何你以前没有返回的新信息,现在你有另外一个你需要处理的结果集,这在我看来只是一大堆不必要的开销。
答案 2 :(得分:1)
我首先要说这是一个非常糟糕的设计。根据您当前的方法,您需要运行多个子查询或与表别名连接以获得您想要的结果。
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
...
attribute
attribute_sid (eg, string id)
product
product_id
name
...
product_attribute
product_id (foreign key to product table)
attribute_sid (foreign key to attribute table)
value
这样,您就拥有了一个明确的属性列表,以及每个产品的单个属性值。
SELECT attribute_sid, value FROM product_attribute WHERE product_id = 1
...将检索所有属性和值,这些属性和值可以方便地放在dict
,array
或map
中。