2016-07-01 48 views
1

比方说,我有一个表customers返回行,如果匹配所有列表值

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

和一张桌子languages

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

和一张桌子cust_lang

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

给出一个列表: “英语”, “西班牙”, “葡萄牙”] 使用WHERE IN的名单,它仍然会返回客户ids 1,2因为它们匹配“英语”和“西班牙语”。 但是,结果应为0行,因为没有客户匹配所有三个术语。 我只想要客户id返回,如果它匹配cust_lang表。 例如,给定一个列表:[“English”,“Spanish”] 我想让结果成为客户ID 1,因为他一个人说两种语言。

编辑:@GordonLinoff - 这工程!

现在,使其更加复杂,有什么不对的其他相关查询:

假设我也有一个表degrees

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

相应的连接表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));` 

编辑2:我想我解决了它。我无意中在那里有额外的选择陈述。

回答

4

您可以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 
+0

如果我们改正'l.language'的'where' –

1

这是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) 
相关问题