Return 行仅匹配所有列表值

Return rows only if matches all list values

假设我有一个 table customers:

-----------------
|id|name|country|
|1 |Joe |Mexico |
|2 |Mary|USA |
|3 |Jim |France |
-----------------

还有一个table languages:

-------------
|id|language|
|1 |English |
|2 |Spanish |
|3 |French |
-------------

还有一个table cust_lang:

------------------
|id|custId|langId|
|1 |1 |1 |
|2 |1 |2 |
|3 |2 |1 |
|4 |3 |3 |
------------------

给定一个列表:["English"、"Spanish"、"Portugese"] 使用 WHERE IN 作为列表,它仍然会 return id 为 1,2 的客户,因为他们匹配 "English" 和 "Spanish"。 但是,结果应该是 0 行 returned,因为没有客户匹配所有三个术语。 如果匹配 cust_lang table,我只希望客户 ID 为 return。 例如,给定一个列表:["English", "Spanish"] 我希望结果是客户 ID 1,因为他一个人会说两种语言。

编辑:@GordonLinoff - 有效!!

现在让它变得更复杂,这个额外的相关查询有什么问题:

假设我也有一个 table degrees:

-----------
|id|degree|
|1 |PHD |
|2 |BA |
|3 |MD |
-----------

一个对应的join table cust_deg:

------------------
|id|custId|degId |
|1 |1 |1 |
|2 |1 |2 |
|3 |2 |1 |
|4 |3 |3 |
------------------

以下查询无效。但是,它是两个相同查询的组合。结果应该只是匹配两个列表的行,而不是一个列表。

SELECT * FROM customers C
    WHERE C.id IN (
    SELECT CL.langId FROM cust_lang CL
    JOIN languages L on CL.langId = L.id 
    WHERE L.language IN ("English", "Spanish")
    GROUP BY CL.langID 
    HAVING COUNT(*) = 2) 
AND C.id IN (
        SELECT CD.custId FROM cust_deg CD
        JOIN degrees D ON CD.degID = D.id 
        WHERE D.degree IN ("PHD", "BA") 
        GROUP BY CD.custId HAVING COUNT(*) = 2));`

EDIT2:我想我已经修好了。我不小心在那里有一个额外的 select 语句。

您可以使用 group byhaving 执行此操作:

select cl.custid
from cust_lang cl join
     languages l
     on cl.langid = l.id
where l.language in ('English', 'Spanish', 'Portuguese')
group by cl.custid
having count(*) = 3;

例如,如果您只想检查两种语言,那么您只需更改 WHERE ... INHAVING 条件,例如:

where l.language in ('English', 'Spanish')

having count(*) = 2

这几乎是 Gordon 的回答,但它的好处是在语言列表上更加灵活,并且不需要对 having 子句进行任何更改。

with my_languages as (
    select langId from languages
    where language in ('English', 'Spanish')
)
select cl.custId
from cust_lang as cl inner join my_languages as l on l.langId = cl.langId
group by cl.custId
having count(*) = (select count(*) from lang)