Оставлено соединение, возвращающее лишние строки T-SQL? - PullRequest
1 голос
/ 07 мая 2010

У меня следующий запрос:

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 ]

4 голосов
/ 07 мая 2010

Я делаю левое соединение - почему оно добавляет дополнительную строку?

Вы делаете INNER JOIN.

Условия как это:

and r.ACADEMIC_TERM='Fall'

эффективно отфильтровывает фальшивые строки, созданные левым соединением, оставляя только записи, которые будут возвращены INNER JOIN при тех же условиях.

Причина, по которой вы получаете две записи на academic, заключается в том, что в residency на academic есть две записи, которые удовлетворяют другому условию соединения.

Если вы хотите вернуть только один residency за academic, вам нужно определить, какой из них будет.

1 голос
/ 07 мая 2010

Давайте рассмотрим два разных варианта получения того, что вы хотите. Сначала нужно исправить общий запрос, чтобы переместить любое место в таблице 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%')  
1 голос
/ 07 мая 2010

Ваше объединение берет строки, которые соответствуют критериям из вашей левой таблицы, и соединяет их со строками из правой таблицы, в любом случае, если "a.PEOPLE_CODE_ID = r.PEOPLE_CODE_ID" истинно, эта комбинация будет возвращена.Очевидно, это условие выполняется для 2 строк для каждой имеющейся левой строки.

1 голос
/ 07 мая 2010

Причина, по которой вы получаете дополнительные строки, заключается в том, что вы добавили условия в условие 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%')
0 голосов
/ 07 мая 2010

Не совсем уверен, почему это происходит, потому что я не знаю взаимосвязи между двумя таблицами, которые вы используете (один ко многим, много ко многим и т. Д.). Однако я могу сказать вам, что когда вы добавляете столбец из таблицы "left join" в предложении WHERE, он отменяет левое соединение и делает его внутренним соединением.

0 голосов
/ 07 мая 2010

Что на самом деле в вашей резидентской таблице? Что значит

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

дать в результате?

LEFT JOIN предоставит вам все строки в вашей таблице ACADEMIC, независимо от того, есть ли соответствующая строка в вашей таблице RESIDENCY. Но если в RESIDENCY есть несколько совпадающих строк для вашего условия соединения, вы все равно получите несколько строк назад, так же, как и при INNER JOIN.

...