【问题标题】:Return rows only if matches all list values仅当匹配所有列表值时才返回行
【发布时间】:2016-07-01 01:29:12
【问题描述】:

假设我有一张桌子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 |
------------------

给定一个列表:["English", "Spanish", "Portugese"] 使用WHERE IN 作为列表,它仍然会返回ID 为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));`

EDIT2:我想我修好了。我不小心在其中有一个额外的 select 语句。

【问题讨论】:

    标签: sql where


    【解决方案1】:

    您可以使用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
    

    【讨论】:

    • 如果我们将where 更正为l.language,则此方法有效
    【解决方案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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      相关资源
      最近更新 更多