Возвращает строки, даже если запись не существует ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ

#sql-server #left-join

#sql-server #левое соединение

Вопрос:

У меня есть 2 таблицы ниже:

 Table_1
[Group No] [Test No] [Description]
123        1         [First Test]
123        2         [Second Test]
123        3         [Third Test]

Table_2
[Sample No] [Test No] [Result Description]
ABC         1         [Some More Result]
ABC         3         [Some Result]
DEF         1         [A Result]
DEF         2         [Results More]
DEF         3         [Bad Results]
  

Вот мой запрос:

 SELECT Table_1.[Group No], Table_1.[Test No], Table_1.Description, Table_2.[Result Description]
FROM Table_1 
LEFT OUTER JOIN Table_2 ON Table_1.[Test No] = Table_2.[Test No]
WHERE (Table_1.[Group No] = '123') AND (Table_2.[Sample No] = 'ABC')
  

запрос Джакобсона:

 SELECT Table_1.[Group No], Table_1.[Test No], Table_1.Description, Table_2.[Result Description]
FROM Table_1 
LEFT OUTER JOIN Table_2 ON Table_1.[Test No] = Table_2.[Test No]
WHERE (Table_1.[Group No] = '123') 
  AND (Table_2.[Sample No] IS NULL OR Table_2.[Sample No] = 'ABC')
  

Это возвращает:

 [Group No] [Test No] [Description] [Result Description]
123        1         [First Test]  [Some More Result]
123        3         [Third Test]  [Some Result]
  

Но чего я действительно хочу, так это:

 [Group No] [Test No] [Description] [Result Description]
123        1         [First Test]  [Some More Result]
123        2         [Second Test] NULL
123        3         [Third Test]  [Some Result]
  

Возможно ли это? Я хотел бы вернуть запись с тестом № 2. Однако, как мне присоединиться к записи, которая не существует? Или это просто невозможно? Каковы альтернативы?

Ответ №1:

Несмотря на корректное использование внешнего соединения, вы ограничиваете результирующий набор случаями, когда значение присутствует в Table_2, включая столбец из этой таблицы в ваше предложение WHERE. Если вам нужны записи, в которых номер образца равен ABC, ИЛИ в Table_2 нет записи, вам нужно сделать это:

 SELECT Table_1.[Group No], Table_1.[Test No], Table_1.Description, Table_2.[Result Description]
FROM Table_1 
LEFT OUTER JOIN Table_2 ON Table_1.[Test No] = Table_2.[Test No]
WHERE (Table_1.[Group No] = '123') 
  AND (Table_2.[Sample No] IS NULL OR Table_2.[Sample No] = 'ABC')
  

В качестве альтернативы, вы можете отфильтровать результаты из Таблицы_2 при присоединении к ней (что в этом случае читается немного более чисто):

 SELECT Table_1.[Group No], Table_1.[Test No], Table_1.Description, Table_2.[Result Description]
FROM Table_1 
LEFT OUTER JOIN Table_2 ON Table_1.[Test No] = Table_2.[Test No] AND Table_2.[Sample No] = 'ABC'
WHERE (Table_1.[Group No] = '123') 
  

Это должно выполнить то же самое. Важным выводом здесь является то, что предложение WHERE фильтрует результаты объединения ваших таблиц. Если вы используете внешние соединения, но хотите выполнить фильтрацию по таблицам с внешним соединением, вы должны обработать случай, когда на дальней стороне соединения не существует записи.

Комментарии:

1. Привет, Джакобсон, это по-прежнему дает те же результаты, я все еще не получаю строку с тестом № 2. Это как-то связано с ОБЪЕДИНЕНИЕМ?

2. Это странно… Какой именно запрос вы используете сейчас? Пожалуйста, отредактируйте свой вопрос, чтобы включить его (вы можете использовать форматирование исходного кода в вопросе, но не в комментарии).

3. Привет, Джакобсон, второй запрос, похоже, дал требуемые результаты. Я отредактировал свой первоначальный вопрос, включая первый запрос, который вы предложили — это не сработало, но второй сработал.

4. Ах, я протестировал это и понимаю, почему первый запрос исключает тест 2: поскольку он не фильтрует Table_2 при объединении, мы получаем запись для теста 2, присоединенную к образцу DEF. Затем мы фильтруем результаты для тех, которые не содержат выборки, или используем образец ABC, чтобы исключить запись для теста 2. (Самый простой способ увидеть, что происходит, — это выполнить SELECT * из соединенных таблиц без предложения WHERE). Итак, фильтрация Таблицы_2 при объединении, а затем фильтрация по группе после объединения — это правильный путь!

5. Спасибо, это ответ! Я должен помнить, что фильтрация в предложении WHERE ограничивает представление и что я должен делать это с помощью предложения FROM, правильно?