【问题标题】:SQL Query with two different filters具有两个不同过滤器的 SQL 查询
【发布时间】:2019-10-02 17:02:40
【问题描述】:

我有一个页面显示来自 DB 的所有汽车。 我有两个过滤器,都是多选过滤器。 例如

过滤器 1 - 颜色

红、绿、蓝

过滤器 2 - 品牌

宝马、本田、现代

我已经完成了下面的查询

Select * from cars
JOIN term_car_relationships  
ON cars.id = term_cars_relationships.car_id 
 WHERE term_cars_relationships.term_id in (6,2,3) 
GROUP BY cars.id

在上面的查询term_id

6 = 蓝色(颜色)

2 = 绿色(颜色)

3 = BNW(品牌)

但是通过上述查询,我​​将获得所有具有蓝色或绿色或宝马品牌的汽车 但是如何改变我得到蓝色或绿色的宝马。

我有 3 个处理这些类别的表。

分类表

taxonomy_id | taxonomy_title
1           | Color
2           | Brand

术语列表

term_id  |  term_name  |  taxonomy_id
1        | Blue        | 1
2        | Red         | 1
3        | BMW         | 2
4        | Honda       | 2

term_cars_relationships 表

 term_id | car_id   
     1      |  1
     1      |  2
     2      |  3

【问题讨论】:

  • 除非数据集很大,否则考虑将整个数据集加载到一些 json 中并在那里处理过滤。

标签: php mysql sql join


【解决方案1】:

您应该加入term_cars_relationships 表两次:

    SELECT * FROM cars
    JOIN term_car_relationships c ON cars.id = c.car_id 
    JOIN term_car_relationships b ON cars.id = b.car_id 
    WHERE c.type_of_category = 'color'
    AND b.type_of_category = 'brand'
    AND c.term_id in (6,2)
    AND b.term_id in (3)
    GROUP BY cars.id

请注意,我使用 b.term_id in (3) 而不是 b.term_id = 3,因为我假设您可能想要选择多个品牌。

【讨论】:

  • 您能否在我更新的问题中检查我的表结构。
【解决方案2】:

您可以为每个术语类别使用单独的连接来构建查询,也可以为每个类别使用单独的过滤条件。

SELECT cars.*, colorTerms.*, brandTerms.* 
FROM cars
INNER JOIN term_car_relationships AS carColorTerms
   ON cars.id = carColorTerms.car_id
INNER JOIN term_list AS colorTerms 
   ON carColorTerms.term_id = colorTerms.term_id AND colorTerms.taxonomy_id = 1
INNER JOIN term_car_relationships AS carBrandTerms
   ON cars.id = carBrandTerms.car_id
INNER JOIN term_list AS brandTerms 
   ON carBrandTerms.term_id = brandTerms.term_id AND brandTerms.taxonomy_id = 2
WHERE colorTerms.term_id IN (6, 2)
   AND brandTerms.term_id IN (3)

当然,要构造此查询,您需要在查询之前知道术语的类型。


另外,使用GROUP BY cars.id 而不使用聚合可能是一个问题的迹象,或者只是不是得到你想要的东西的正确方法。如果您只需要cars 表中的信息,您应该只需要SELECT DISTINCT cars.*。以这种方式使用 GROUP BY 最终会得到每辆车只匹配一个颜色品牌的数据。


随着对原始问题的编辑添加的复杂性,另一种可能性出现了......

SELECT cars.* -- You should really just select the fields you want, and may have to in some configurations (see GROUP BY)
FROM cars AS c
INNER JOIN term_car_relationships AS tcr ON c.car_id = tcr.car_id
INNER JOIN term_list AS tl ON tcr.term_id = tl.term_id
WHERE tcr.term_id IN (6, 2, 3)
GROUP BY cars.car_id -- In some configurations of MySQL, and most other RDBMSes, you must specify every SELECTed non-aggregated field here
HAVING COUNT(DISTINCT tl.taxonomy_id) 
   = ( SELECT COUNT(DISTINCT taxonomy_id) 
       FROM term_list 
       WHERE term_id IN (6, 2, 3)
     )

注意:这个最终解决方案实际上不再要求您提前了解术语分类法,并且不会随着更多分类法需要支持而增长;所以虽然它的作用不太明显,但绝对值得考虑。

【讨论】:

  • 实际上 type_of_category 存储了分类(颜色或品牌)的 ID,即 1 或 2 。那么我应该使用ON cars.id = colorTerms.car_id AND colorTerms.type_of_category = '1' 吗?这是一个好习惯吗?
  • 我只是按照你对表格的描述,有一个 id/int 肯定更好。在连接而不是在哪里进行额外的类别过滤是有争议的; 从概念上来说,JOIN 发生在 WHERE 之前,因此在此处包含过滤可以减少中间结果的大小,但是 MySQL 在可以提供帮助时尽早应用 WHERE 条件非常好。我更喜欢将其保留在连接中;它有助于识别正在连接的表的实例用于什么(通常别名不能足够描述)并最小化垂直扫描以确定这一点。
  • 我真的很抱歉造成混乱,我在这方面工作了很长时间,目前我的大脑无法正常工作。请检查我更新的问题。我已经给出了我的表结构。请检查。
  • 现在变得有点复杂了,但我已经更新了我提供的查询。
  • 是的,你是对的,我是否应该更改我的表结构,以便只有 2 个表用于术语,这样我的 JOIN 就会减少,例如 term_list (term_id , taxonomy_name ,term_name) 值会像(1,Color,Red and 2,Color,BLue 等),第二个表将是relationship (term_id,movie_id)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多