Sql 如何编写一个排除某些结果,但包含缺少用于排除的关联的结果的查询?

Sql 如何编写一个排除某些结果,但包含缺少用于排除的关联的结果的查询?,sql,mysql,Sql,Mysql,我有一个用于查询服务条款的搜索表,我称之为“条款”。条款可能在has中有某些资格要求,并且属于许多关系,但它们也可能根本没有任何要求。我的问题是,当我根据某一特定要求排除某些规定时,那些根本没有要求的规定也被排除在外 表结构: provisions * id * title requirements * id * title provisions_requirements * provision_id * requirement_id 假设一个需求如下所示: Canadian Citize

我有一个用于查询服务条款的搜索表,我称之为“条款”。条款可能在has中有某些资格要求,并且属于许多关系,但它们也可能根本没有任何要求。我的问题是,当我根据某一特定要求排除某些规定时,那些根本没有要求的规定也被排除在外

表结构:

provisions
* id
* title

requirements
* id
* title

provisions_requirements
* provision_id
* requirement_id
假设一个需求如下所示:

Canadian Citizenship (id 4)
这将以如下形式呈现:“不包括要求:加拿大公民身份的服务”

因此,查询的排除部分是:

requirements.id NOT IN (4)
但是,我只得到至少有一个要求的条款,因为那些没有要求的条款不包括在联接中

实际查询如下所示:

SELECT DISTINCT `provisions`.id 
FROM `provisions` 
LEFT OUTER JOIN `provisions_requirements` 
  ON `provisions_requirements`.provision_id = `provisions`.id 
LEFT OUTER JOIN `requirements` 
  ON `requirements`.id = `provisions_requirements`.requirement_id 
WHERE (requirements.id NOT IN ('1')) 
LIMIT 0, 10
试试这个:

SELECT DISTINCT `provisions`.id 
FROM `provisions` 
LEFT OUTER JOIN `provisions_requirements` ON `provisions_requirements`.provision_id = `provisions`.id 
LEFT OUTER JOIN `requirements` ON `requirements`.id = `provisions_requirements`.requirement_id and (requirements.id NOT IN ('1'))
LIMIT 0, 10
那么你想要所有的服务,除了那些需要加拿大公民身份的服务(req_id 4)

试试这个:它试图与4的
要求\u id
相匹配,但是
WHERE
子句中的条件使得只有发现不匹配的条款才满足该条件

SELECT p.id
FROM provisions p LEFT OUTER JOIN provisions_requirements r
 ON (p.id = r.provision_id AND r.requirement_id IN (4))
WHERE r.requirement_id IS NULL
LIMIT 0, 10;

不需要有明显的
DISTINCT
。不需要连接到
需求表。

您的查询在99%中,只需包含一个NULL测试

SELECT
     P.id
FROM
     Provisions P
WHERE
     NOT EXISTS
     (
          SELECT
               *
          FROM
               Provision_Requirements PR
          WHERE
               PR.provision_id = P.id AND
               PR.requirement_id = 4
     )
SELECT DISTINCT `provisions`.id 
FROM `provisions` 
LEFT OUTER JOIN `provisions_requirements` 
  ON `provisions_requirements`.provision_id = `provisions`.id 
LEFT OUTER JOIN `requirements` 
  ON `requirements`.id = `provisions_requirements`.requirement_id 
WHERE (requirements.id NOT IN ('1')) 
or requirements.id is NULL -- test for null
LIMIT 0, 10

这将包括那些在我提供的规定要求表中没有条目的行

+1-我倾向于在连接条件中使用此类子句,而不是像“WHERE x=y或x为NULL”+1这样的规定,尽管格式很难理解(必须限制编辑权限的使用)@Andomar:感谢+1。FWIW,这不是我在实际代码中使用的格式。我支持您使用自己喜欢的代码格式标准。各自为政!卓越、优雅的解决方案,我喜欢它(它很有效,我实现了它)。我的最后一个查询不像您的查询那么容易阅读,但这是因为这些查询是用ActiveRecord构建的,ActiveRecord坚持选择“不同”等。非常感谢您提供的解决方案。@adriandz:我很好奇您使用的是哪种ActiveRecord实现。这是Ruby on Rails吗?为什么它要坚持与众不同?听起来这是一种不必要地对临时表进行排序的好方法,这会降低性能。为什么在PR中加入R?R看起来没用,还是我遗漏了什么。。。哎呀。。。我最初编写它时加入了对需求的连接,直到我意识到他使用的是ID,不管怎样,ID在多对多表中。我将修复它-1一个带有需求“1”和“4”的规定将匹配您的查询,尽管它不应该匹配-1这将找到所有需求。问题是找到那些不需要加拿大公民身份的要求。@Andomar,这不会找到所有要求,只会找到requirements.id不在('1')中的要求,这意味着什么。这是从他的示例查询中得到的,他在文本中谈到了id 4,但他的查询示例是针对id 1的,我使用的是,如果该规定同时包含要求1和4,我认为它不应该出现在结果集中。@Andomar,请参阅我之前对您的评论,他在示例查询中要求“1”,但在文本中要求“4”。我的答案使用“notin(1)”,如果他们真的想要两者,那么将其编码为“notin(1,4)”,这很重要