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 by
和 having
执行此操作:
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 ... IN
和 HAVING
条件,例如:
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)
假设我有一个 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 by
和 having
执行此操作:
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 ... IN
和 HAVING
条件,例如:
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)