SQL:多对多关系和“ ALL”子句

时间:2018-09-26 09:49:49

标签: mysql sql relational-division

我有一个表products和一个表locations,它们与一个表products_locations以多对多的关系链接在一起。现在,客户可以选择一组产品,而我想运行一个查询,该查询只选择所有选定产品都可用的位置。

起初这似乎很简单,但是我发现自己对如何实现这一目标感到困惑。最初我以为我可以使用类似的东西获得所有正确的位置ID

SELECT location_id
FROM products_locations
WHERE product_id = ALL [the user selected product ids]

但经过一番思考,这似乎也没有道理(products_locations的结构非常简单[product_id, location_id]

任何有关如何构造这样的查询的建议将不胜感激。我觉得我正在忽略一些基本知识。

编辑:我正在使用mysql语法/方言

快速示例:给出以下表格

| products   | | locations | | products_locations       |
| id | name  | | id | name | | product_id | location_id |
|------------| |-----------| |--------------------------|
| 1  | prod1 | | 1  | locA | | 1          | 2           |
| 2  | prod2 | | 2  | locB | | 2          | 1           |
| 3  | prod3 | |-----------| | 2          | 2           |
|------------|               | 3          | 1           |
                             |--------------------------|

如果用户选择产品1和2,则查询应仅返回位置2。如果用户选择产品2和3,则查询应返回位置1。对于1、2和3,没有位置有效,对于产品2,两个位置都有效。

1 个答案:

答案 0 :(得分:0)

我想出一个可以满足我需要的查询。尽管它不像我希望的那样干净,但对于我要查询的内容,这似乎是一种可靠的方法:

SELECT t.location_id
FROM (SELECT location_id, COUNT(*) as n_hits
      FROM products_locations
      WHERE product_id IN [the user selected products]
      GROUP BY location_id) t
WHERE n_hits = [the number of user selected products];

说明:

  1. 我创建一个临时表t,其中包含每个location_id(在用户的选择中具有至少一个匹配产品)以及位置在用户的选择中与某个产品匹配的次数。这可以通过按location_id对查询进行分组来实现。
  2. 我从该临时表location_id中选择了t,其中命中次数等于用户选择的产品数。如果该数字更低,我知道至少有一种产品与该位置不匹配。