我有三个表:( SQL小提琴:http://sqlfiddle.com/#!2/f7b33/11)
产品
+----+-----------+
| id | product |
+----+-----------+
| 1 | product_1 |
| 2 | product_2 |
| 3 | product_3 |
+----+-----------+
products_features
+------------+------------+
| product_id | feature_id |
+------------+------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
| 2 | 3 |
| 3 | 4 |
+------------+------------+
功能
+----+-----------+
| id | feature |
+----+-----------+
| 1 | feature_1 |
| 2 | feature_2 |
| 3 | feature_3 |
| 4 | feature_4 |
+----+-----------+
然后我选择这样:
SELECT products.product,
GROUP_CONCAT(features.feature) AS features
FROM products
LEFT JOIN products_features
ON product_id = products.id
LEFT JOIN features
ON products_features.feature_id = features.id
GROUP BY products.id
得到类似的东西:
+-----------+-----------------------------------------+
| product | features |
+-----------+-----------------------------------------+
| product_1 | feature_1,feature_2,feature_3,feature_4 |
| product_2 | feature_1,feature_3 |
| product_3 | feature_4 |
+-----------+-----------------------------------------+
所以,一切都很棒,但是,我想做的只是拥有feature_1和feature_3的东西,同时还能获得其他功能。
换句话说,我想写一个能让我得到的查询:
+-----------+-----------------------------------------+
| product | features |
+-----------+-----------------------------------------+
| product_1 | feature_1,feature_2,feature_3,feature_4 |
| product_2 | feature_1,feature_3 |
+-----------+-----------------------------------------+
我试过了:
SELECT products.product,
GROUP_CONCAT(features.feature) AS features
FROM products
LEFT JOIN products_features
ON product_id = products.id
RIGHT JOIN features
ON products_features.feature_id = features.id AND features.feature in ('feature_1','feature_3')
GROUP BY products.id
但我当然得到:
+-----------+---------------------+
| product | features |
+-----------+---------------------+
| (null) | feature_4,feature_2 |
| product_1 | feature_1,feature_3 |
| product_2 | feature_3,feature_1 |
+-----------+---------------------+
因此,虽然我现在知道product_1和product_2是具有这些功能的那些,但我看不到他们拥有的其他功能。
哪些查询可以让我指定feature_1和feature_3并获得以下回复?
+-----------+-----------------------------------------+
| product | features |
+-----------+-----------------------------------------+
| product_1 | feature_1,feature_2,feature_3,feature_4 |
| product_2 | feature_1,feature_3 |
+-----------+-----------------------------------------+
答案 0 :(得分:3)
我认为最常见的方法是使用having
子句:
SELECT products.product,
GROUP_CONCAT(features.feature) AS features
FROM products
LEFT JOIN products_features
ON product_id = products.id
LEFT JOIN features
ON products_features.feature_id = features.id
GROUP BY products.id
HAVING sum(features.feature = 'feature_1') > 0 and
sum(features.feature = 'feature_3') > 0;
having
语句中的每个子句都计算给定要素出现的次数。 and
要求两个要素都在最终结果集中。
编辑:
鉴于你的陈述结构,你也可以这样做:
HAVING find_in_set('feature_1', features) > 0 and
find_in_set('feature_3', features) > 0;
这是有效的,因为您正在生成包含要素列表的列,并且您使用逗号作为该列表的分隔符。
答案 1 :(得分:1)
从group_concat
返回数据然后将结果拆分回前端是不行的。它不仅会导致资源的低效使用,而且还可能导致分裂错误(例如:想象当某个功能出现时会发生什么,并且恰好包含,
)。
不使用group_concat
的第三个主要原因是它对长度有限制。我没有重新解释方向盘,但请查看question以获取更多信息。
最好的方法是返回给定产品的所有匹配功能,然后只需循环处理它们。它应该很简单(实际上,大多数UI组件,无论是否为Web,都希望收到一个集合来显示它们,这就是你发送给它们的内容)。
此外,您很可能已经拥有要检查的功能的ID,因此检查它们而不是字符串会更有效。
我最后的评论是你实际上并不需要左连接。左连接将返回左侧的所有元素,无论它们是否在右侧匹配。但是,您需要右侧有2个元素(2个特征),这使得查询相互矛盾。你只需要一个内部联接。
这是我要使用的查询:
SELECT p.product, f.feature FROM products p
JOIN (
SELECT product_id FROM products_features
WHERE feature_id IN (1, 3)
GROUP BY product_id
HAVING count(*) = 2
) pf ON p.id = pf.product_id
JOIN products_features pf2 ON p.id = pf2.product_id
JOIN features f ON pf2.feature_id = f.id
这是该查询的fiddle。