如何创建一个查询,选择具有特定语句的产品,其中特征语句由“和”或“或”条件构成,具体取决于它们所属的组?
情况描述
测试环境
http://sqlfiddle.com/#!12/f4db7
“或”查询
它适用于那些没有功能的产品。
SELECT product_id
FROM product_features
WHERE product_features.feature_id IN (
SELECT feature_id FROM features
LEFT JOIN feature_groups
ON features.feature_group_id = feature_groups.feature_group_id
WHERE feature_id IN (11, 12, 13) AND feature_groups.disjunction = TRUE
)
GROUP BY product_id
“和”查询
无法使用此查询,因为不知道disjunction为false的要素数。
SELECT product_id FROM product_features
WHERE feature_id IN (43, 53, 63)
GROUP BY product_id
HAVING COUNT(DISTINCT feature_id) = 3
答案 0 :(得分:1)
更简单,更快捷:
SELECT DISTINCT pf.product_id
FROM product_features pf
LEFT JOIN features f USING (feature_id)
LEFT JOIN feature_groups fg USING (feature_group_id)
WHERE (f.feature_id = ANY (_my_arr)
AND fg.disjunction)
OR _my_arr = '{}';
...其中_my_arr
可以是'{11, 12, 13}'::int[]
或'{}'::int[]
。如果_my_arr
将NULL
改为使用_my_arr IS NULL
。
由于operator precedence AND
在OR
之前绑定,因此不需要括号。但它们可能会提高可读性。
DISTINCT
或GROUP BY
..在这里也不错。
AND fg.disjunction
..因为这是一个布尔类型,你可以缩短语法。
JOIN通常比另一个IN
子句更快。
USING
只是一个符合您(有用的!)命名约定的符号快捷方式。
或者,甚至更快(超过1个功能) - 并且更容易分割案例:
SELECT product_id
FROM products p
WHERE EXISTS (
SELECT 1
FROM product_features pf
JOIN features f USING (feature_id)
JOIN feature_groups fg USING (feature_group_id)
WHERE pf.product_id = p.product_id
AND f.feature_id = ANY (_my_arr)
AND fg.disjunction
)
OR _my_arr = '{}';
我宁愿根据输入(具有功能/没有功能)在您的应用中拆分案例。与第二种形式有关。
这是关系划分的经典案例。在这个相关问题下,我们已经汇集了一整套查询技术来处理它:
How to filter SQL results in a has-many-through relation
可能是:
SELECT product_id
FROM product_features p1
JOIN product_features p2 USING (product_id)
JOIN product_features p3 USING (product_id)
...
WHERE p1.feature_id = 43
AND p2.feature_id = 53
AND p3.feature_id = 63
...
我在示例中忽略了NOT feature_groups.disjunction
,因为它也不在问题中。如果需要,可以添加它
在构建查询之前,我会选择有效的feature_id。