我应该在SQL中使用什么Join

时间:2013-04-05 15:50:14

标签: sql sql-server-2008

我的数据库中有四个表: 包含ID(PK)和名称的人员。 Person_Skill包含ID(PK),PID(FK),技能(FK)和SkillLevel(FK)。 包含ID(PK)和SkillLabel的技能。 包含ID(PK)和名称的SkillLevel。

每项技能的等级从0到7

现在我想显示该人拥有的所有技能(包括技能等级= 0)

Select
   [dbo].Person.Name as Name,
   [Skill].SkillLabel as SkillName,
   [Person_Skill].[SkillLevel] as SkillLevel
From
   ([dbo].Person inner join [dbo].[Person_Skill] ON [dbo].[Person_Skill].PID= Person.ID)
   inner join [dbo].[Skill] ON [dbo].[Person_Skill].Skill=Skill.ID

以上代码仅显示此人从1级到7级的技能。

我相信我只从1级到7级获得技能的原因是因为人员表仅包含1级到7级的技能,但我不确定这一点。我从其他人那里得到了数据库。如果我的假设是正确的,那么无论如何都要这样做吗?获得技能表中的所有技能并显示该人员的技能等级(包括技能等级= 0)。

Sample Data:
Person
ID    Name
----------
1     Michael
2     Alex

Person_Skill
ID    PID  SkillID Skill_Level
5     1     10          5
6     2     11          1
7     1     12          7
8     1     13          5

Skill
ID    Name
10    java
11    C++
12    HTML
13    ASP
14    C
15    .NET
16    C#
17    Objective

The expect results are;
Name    SkillName SkillLevel
----------------------------
Alex    java        0
Alex    C++         1
Alex    HTML        0
Alex    ASP         0
Alex    C           0
Alex    .NET        0
Alex    C#          0
Alex    Objective C 0
Michael    java      5
Michael    C++       0
Michael    HTML      7
Michael    ASP       0
Michael    C         0
Michael    .NET      5
Michael    C#        0
Michael    Objective C0

当前查询仅输出

Alex    C++         1
Michael    java      5
Michael    HTML      7
Michael    .NET      5

3 个答案:

答案 0 :(得分:2)

编辑,如果您想要返回每个人的所有技能名称,那么您将需要使用:

select d.p_name,
  d.s_name SkillName,
  coalesce(ps.Skill_Level, 0) Skill_Level
from
(
  select p.id p_id, p.name p_name, s.id s_id, s.name s_name
  from person p
  cross join skill s
) d
left join person_skill ps
  on d.p_id = ps.pid
  and d.s_id = ps.skillid
left join skill s
  on ps.skillid = s.id

请参阅SQL Fiddle with Demo

如果您想要包含所有Skills 0-7,那么您将需要使用LEFT JOIN。您的查询将类似于以下内容:

select p.Name as Name,
   s.SkillLabel as SkillName,
   ps.[SkillLevel] as SkillLevel
from [dbo].[Skill] s
left join [dbo].[Person_Skill] ps
  on ps.Skill=s.ID
left join [dbo].Person p
  on ps.PID = p.ID

编辑,没有看到任何数据,很难确定。但是,如果要检索所有SkillLevels,则需要包含该表。您可能需要使用:

select 
  p.Name as Name,
  s.SkillLabel as SkillName,
  sl.[Name] as SkillLevel
from SkillLevel sl
left join [dbo].[Person_Skill] ps
  on ps.SkillLevel=sl.ID
left join [dbo].[Skill] s
  on ps.Skill = s.Id
left join [dbo].Person p
  on ps.PID = p.ID

<击>

答案 1 :(得分:0)

您希望使用LEFT JOIN tableAtableb内部加入tableA会返回tableB的所有记录,无论是否存在匹配项0

因此,如果没有技能为person的人,您仍会收到所有{{1}}条记录。

答案 2 :(得分:0)

INNER JOIN只会返回两边都匹配的行。所以在你的代码中,如果一个人没有0等级的技能,就不会被退回。

您可以执行LEFTRIGHT联接,这些会从左侧或右侧的表中获取所有行。我你可能想要使用左连接,但是在不了解你的架构的情况下,很难肯定地说。有关不同联接类型差异的更多详细信息,请参阅问题Left join and Left outer join in SQL Server的答案