左连接返回额外的行T-SQL?

时间:2010-05-07 14:51:30

标签: sql tsql left-join

我有以下查询:

select * from ACADEMIC a
left join RESIDENCY r on a.PEOPLE_CODE_ID = r.PEOPLE_CODE_ID
where a.ACADEMIC_TERM='Fall' 
and r.ACADEMIC_TERM='Fall'
and a.ACADEMIC_SESSION=''
and a.ACADEMIC_YEAR = (Select Year(GetDate())) 
and r.ACADEMIC_YEAR = (Select Year(GetDate()))
and (CLASS_LEVEL LIKE 'FR%'
     OR a.CLASS_LEVEL LIKE 'SO'
     OR a.CLASS_LEVEL LIKE 'JR'
     OR a.CLASS_LEVEL LIKE 'SR%') 
and r.RESIDENT_COMMUTER='R'

对于数据库中的每个人,它返回两行具有相同信息。然而,当我在没有左连接的情况下执行相同的查询时:

select * from ACADEMIC a
where a.ACADEMIC_TERM='Fall' 
and a.ACADEMIC_SESSION=''
and a.ACADEMIC_YEAR = (Select Year(GetDate())) 
and (CLASS_LEVEL LIKE 'FR%'
     OR a.CLASS_LEVEL LIKE 'SO'
     OR a.CLASS_LEVEL LIKE 'JR'
     OR a.CLASS_LEVEL LIKE 'SR%') 
     ORDER BY PEOPLE_ID

每个人只返回一行。我正在做一个左连接 - 为什么要添加一个额外的行?如果我添加一个正确的连接,它不应该只这样做吗?

(更新了一致性/可读性的格式。)

6 个答案:

答案 0 :(得分:4)

  

我正在进行左连接 - 为什么要添加额外的行?

您正在进行INNER JOIN

这样的条件:

and r.ACADEMIC_TERM='Fall'

有效地过滤掉左连接产生的假行,只留下INNER JOIN在相同条件下返回的记录。

原因是每个academic获得两条记录的原因是residencyacademic有两条记录满足其他连接条件。

如果您希望每residency只返回一个academic,则需要定义它是哪一个。

答案 1 :(得分:1)

您获得额外行的原因是您在左连接表的where子句中添加了条件。将r.RESIDENT_COMMUTER ='R'等条件移到join子句中,您将不会遇到这些问题。

例如

select * from ACADEMIC a
left join RESIDENCY r on a.PEOPLE_CODE_ID = r.PEOPLE_CODE_ID
and r.ACADEMIC_YEAR = (Select Year(GetDate()))
and r.RESIDENT_COMMUTER='R'
and r.ACADEMIC_TERM='Fall'
where a.ACADEMIC_TERM='Fall' 
    and a.ACADEMIC_SESSION=''
and a.ACADEMIC_YEAR = (Select Year(GetDate())) 
and (CLASS_LEVEL LIKE 'FR%'
     OR a.CLASS_LEVEL LIKE 'SO'
     OR a.CLASS_LEVEL LIKE 'JR'
     OR a.CLASS_LEVEL LIKE 'SR%')

答案 2 :(得分:1)

您的联接正在从左表中获取符合条件的行,并将它们与右表中的行配对,在每个“a.PEOPLE_CODE_ID = r.PEOPLE_CODE_ID”为真的情况下,将返回此组合。显然,对于每个左手行,这条件满足2行。

答案 3 :(得分:1)

让我们探索两种不同的选择来获得你想要的东西。首先,您需要修复常规查询以将表r上的条件移动到连接。如果您真的需要左连接,请参阅此链接以了解您正在做什么是无关紧要的: http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

并且不要再在生产代码中使用select *,这是不好的做法。

这是固定查询:

select [List columns here do not list the join column twice!] 
from ACADEMIC a 
left join RESIDENCY r on a.PEOPLE_CODE_ID = r.PEOPLE_CODE_ID 
and r.RESIDENT_COMMUTER='R'
and r.ACADEMIC_TERM='Fall' 
and r.ACADEMIC_YEAR = (Select Year(GetDate())) 
where a.ACADEMIC_TERM='Fall'  
    and a.ACADEMIC_SESSION='' 
and a.ACADEMIC_YEAR = (Select Year(GetDate()))  
and (CLASS_LEVEL LIKE 'FR%' 
     OR a.CLASS_LEVEL LIKE 'SO' 
     OR a.CLASS_LEVEL LIKE 'JR' 
     OR a.CLASS_LEVEL LIKE 'SR%')  

如果那样做并不能满足你的需要,那么你可能需要这样做:

select [List columns here  for a and r1, do not list the join column twice!] 
from ACADEMIC a 
left join(select min(people_code_id) from  RESIDENCY r on a.PEOPLE_CODE_ID = r.PEOPLE_CODE_ID 
    and RESIDENT_COMMUTER='R'
    and ACADEMIC_TERM='Fall' 
    and ACADEMIC_YEAR = (Select Year(GetDate())) ) r on a.PEOPLE_CODE_ID = r.PEOPLE_CODE_ID 
left join RESIDENCY r1 on r.PEOPLE_CODE_ID = r1.PEOPLE_CODE_ID 
where a.ACADEMIC_TERM='Fall'  
    and a.ACADEMIC_SESSION='' 
    and a.ACADEMIC_YEAR = (Select Year(GetDate()))  
    and (CLASS_LEVEL LIKE 'FR%' 
     OR a.CLASS_LEVEL LIKE 'SO' 
     OR a.CLASS_LEVEL LIKE 'JR' 
     OR a.CLASS_LEVEL LIKE 'SR%')  

答案 4 :(得分:0)

您的居住表中实际存在什么?什么

SELECT 
  PEOPLE_CODE_ID, 
  COUNT(*) 
FROM 
  residency 
GROUP BY 
  PEOPLE_CODE_ID 
HAVING 
  COUNT(*) > 1

给出结果?

LEFT JOIN将为您提供学术表中的所有行,无论您的RESIDENCY表中是否有匹配的行。但是如果您的连接条件在RESIDENCY中有多个匹配的行,那么您仍将获得多行,就像使用INNER JOIN一样。

答案 5 :(得分:0)

不完全确定它为什么会发生,因为我不知道您正在使用的两个表之间的关系(一对多,多对多等)。但是,我可以告诉您,当您在WHERE子句中的“left joined”表中添加一列时,它会取消左连接并使其成为内连接。