SQL Select 行在不同表上具有相同的 FK 值

SQL Select rows on different tables that have the same FK values

我需要创建一个查询,列出在一个国家/地区能够说所有必需语言的每个人。我有 3 tables(国家/语言/人民)问题是我在 table 国家和人民之间没有 link,但每个 table 都有一个外键“Language_Id”。我的目标是列出每个拥有与 Country 一样多的语言的人。 这是一个例子:

Table 人:

     ID   Name    Language_ID  
1.   1    Paul    1
2.   2    Paul    2
3.   3    Max     1
4.   4    Ben     2
5.   5    Paul    3
6.   6    Ben     3

Table 语言:

     ID   Name
1.   1    English
2.   2    Dutch
3.   3    French

Table 国家:

     ID   Name         Language_ID
1.   1    France       3
2.   2    Netherlands  1
3.   3    Netherlands  2
4.   4    Belgium      2
5.   5    Belgium      3

结果table:

       Name    Country_Name
1.     Paul    France
2.     Paul    Netherlands
3.     Paul    Belgium
4.     Ben     Belgium
5.     Ben     France

因此,Max 被排除在结果之外,因为他不具备所有必需的语言。

我是运行SQLServer 2016标准版。

你能帮我找到解决办法吗?

谢谢!

您可以使用 join 和聚合。一个棘手的部分是计算一个国家/地区内的语言数量,以确保一个人会说所有这些语言:

select p.name, c.name, c.num_languages
from people p join
     (select c.*, count(*) over (partition by name) as num_languages
      from country c
     ) c
     on p.language_id = c.language_id
group by p.name, c.name, c.num_languages
having count(*) = c.num_languages;

一种方法可以使用 CTE 来计算每个国家/地区的语言数,然后计算每个人使用的语言数,并筛选每个人使用的语言至少达到每个国家/地区要求的语言数:

with c as (
    select name Country_Name, language_id, 
      Count(*) over(partition by name) LanguageCount
    from country
), p as (
    select p.name, c.Country_Name, c.LanguageCount,
      Count(*) over(partition by p.name, c.Country_Name)Languages
    from c join people p on p.Language_ID=c.language_id
)
select distinct p.name, p.Country_Name 
from p
where Languages>=LanguageCount;

example fiddle

如果您构建每个人所说的每一种语言组合,并将其与每个国家/地区的要求相匹配,您就会得到想要的东西。

With build as (
    Select Name, cast(language_id as varchar) as languages, language_id as last_lang
    From People
Union All
    Select a.Name, a.languages + ';' + cast(language_id as varchar) as languages
          , b.language_id as last_lang
    From build a Inner Join People b On a.Name=b.Name
    Where a.last_lang<b.language_id
)
Select P.Name, C.Name
From (
    Select Name,
          String_Agg(cast(language_id as varchar), ';') Within Group (Order By language_id) as Language_Reqs
    From Country
    Group By Name
) C Inner Join build P on P.Languages=C.Language_Reqs

也可以修改此技术以确定个人可能缺乏需求的地方。