开发者

Still confused by having and subqueries in MySQL

I'm trying to select products based on facets for a product category page.

The basic structure is:

Product_Facets
--------------------------------
UID      ProductID       FacetID       FacetOptionID
 1           1              1               1
 2           1              1               2
 3           1              2               4
 4           1              2               7
Products
--------------------------------
ProductID      ProductName
    1           Some Widget

I want to select all products which have a facet record set to the correct value for ALL of the user selected facets.

So if I have a request for:

Facet ID 1 set to value 6 AND

Facet ID 2 set to value 97 AND

Facet ID 5 set to value 43 AND

I want the query to ge开发者_如何转开发t all products from the products table that have ALL of those facet records in the facets table for any given product. The query should not return products that only meet some of the requirements.

I think I need to do a sub-query inside of a having clause but I'm not sure how that gets structured?


One method would be using EXISTS clauses, which you could generate dynamically based on the request:

select p.*
from Products p 
where 
   exists (select 1 from Product_Facets where ProductID = p.ProductID
                                        and FacetID = 1
                                        and FacetOptionID= 6)
and
   exists (select 1 from Product_Facets where ProductID = p.ProductID
                                        and FacetID = 2
                                        and FacetOptionID= 97)
and
   exists (select 1 from Product_Facets where ProductID = p.ProductID
                                        and FacetID = 3
                                        and FacetOptionID = 43)

Another method would be straight inner joins (also easily generated dynamically):

select p.*
from Products p
join Product_Facets f1 on p.ProductID = f1.ProductID
         and f1.FacetID = 1 and f1.FacetOptionID = 6
join Product_Facets f2 on p.ProductID = f2.ProductID
         and f2.FacetID = 2 and f2.FacetOptionID = 97
join Product_Facets f3 on p.ProductID = f3.ProductID
         and f3.FacetID = 3 and f3.FacetOptionID = 43

Either method will only return records from Products where Product_Facets records exist for each requested FacetID and FacetOptionID (I assume this is the Value field you mentioned.)


I would prequery from the facets table ONLY for those entities that match and apply HAVING count exactly equal to the criteria you've opted for, then join that to the products table.

The first "PreQuery" applies an "OR" to each combination as testing each row individually... yet the HAVING clause ensures that ALL 3 criteria WERE properly qualified.

SELECT STRAIGHT_JOIN
      P.*
   FROM
      ( select pf.ProductID,
               count(*) as MatchedCriteria
           from
              Product_Facets pf
           where
                 (pf.FacetID = 1 AND FacetOptionID = 6 )
              OR (pf.FacetID = 2 AND FacetOptionID = 97 )
              OR (pf.FacetID = 5 AND FacetOptionID = 43 )
           group by
              pf.ProductID
           having
              count(*) = 3 ) PreQuery

      Join Products p
         on PreQuery.ProductID = p.ProductID
   order by
      p.ProductName
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜