按IN()子句中的大多数匹配对结果进行排序

时间:2013-12-17 01:28:00

标签: mysql

我正在寻找重写使用IN()子句的查询的最佳方法。 我想按照products_adjectives和products_interests中匹配次数最多的产品对结果进行排序。

我有5张桌子。

- products
    title, price, description, etc.
- interests
    interest_id, interest_name
- adjectives
    adjective_id, adjective_name
- products_interests
    product_id, interest_id
- products_adjectives
    product_id, adjective_id

我目前正在使用此查询返回任何符合任何形容词或兴趣的产品。这是一个例子:

SELECT *
  FROM products
    LEFT JOIN products_adjectives
      ON products_adjectives.product_id = products.id
    LEFT JOIN products_interests
      ON products_interests.product_id = products.id
  WHERE products_adjectives.adjective_id IN (3,6,9,12,13) OR products_interests.interest_id IN (2,5,8,12,16,18)
  GROUP BY products.id ORDER BY ABS(products.price)

目前,返回任何adjective_ids或interest_ids中存在的任何产品。该查询将返回任何具有任何adjective_id 3,6,9,12,13或任何interest_id 2,5,8,12,16,18的产品我想继续返回所有结果,但我希望它们按哪些产品包含大多数排序形容词或兴趣的匹配。因此,如果某个产品有形容词3,6,9,10,11,那么我希望在形容为3,4,5,7,8

的产品之前

任何想法或方向都将不胜感激。如果我完全错了(使用IN()子句),请告诉我!

谢谢!

2 个答案:

答案 0 :(得分:1)

我在想下面的内容。您缺少的关键想法是按count(*) DESC排序。此查询的缺点是,如果兴趣或形容词表中没有匹配的记录,则不会提取任何产品。但是,由于我认为你是根据它们的相关性来提取东西,所以你不应该想要与零相关的产品。

SELECT *, count(*) as relevance 
FROM products, products_adjectives, products_interests
WHERE products.id = products_interests.product_id 
  AND products.id = products_adjectives.product_id 
  AND (interest_id IN (14, 22, 78) OR adjective_id IN (8, 17, 26))
GROUP BY products.id
ORDER BY count(*) DESC, price ASC

请参阅小提琴:http://sqlfiddle.com/#!3/838571/2

答案 1 :(得分:0)

您的查询存在问题,因为您在给定产品的兴趣和形容词之间生成笛卡尔积。

解决此问题的最简单方法是计算不同的匹配。因此,以下order by子句应该执行您想要的操作:

ORDER BY (count(distinct interest_id) + count(distinct adjective_id)) desc,
         abs(product.price)

您可以通过其他方式解决此问题,例如计算子查询中的兴趣并计算子查询中的形容词。这将是推荐的方法,特别是如果名单变大。 (比方说,30个匹配的兴趣和30个匹配的形容词会产生一个中间表,产品差不多有一千行。)