Как объединить две таблицы в PostgreSQL с похожими столбцами и оставить несовпадающие поля нулевыми или нетронутыми

#postgresql #left-join #union

#postgresql #левое соединение #объединение

Вопрос:

У меня есть оценка основной таблицы. Я уже объединил эту таблицу с таблицей классов. Теперь я хочу присоединиться к другой таблице, инструктор.

Оценка

ClassID Средняя градация
1 A
2 B
3 B

Класс

ID Класс
1 Математика
2 Английский
3 История
4 Испанский
5 Наука

Инструктор

Класс Инструктор
1 Алиса
2 Боб
4 Чарли

Текущий запрос, который у меня есть

 select * from Grade left join Class on Grade.ClassID = Class.ID
 

Могу ли я каким-либо образом оставить соединение Instructor поверх этого запроса, чтобы в моей таблице было следующее?

ID Класс Средняя градация Инструктор
1 Математика A Алиса
2 Английский B Боб
3 История B
4 Испанский Чарли

Не включая 5-Science, поскольку у него нет ни оценки, ни преподавателя.

По другим причинам я должен сначала присоединиться к Grade.

Спасибо!

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

1. Вы пишете, что должны присоединиться к первому классу — вы имеете в виду, что по какой-то причине это должна быть первая таблица в части «от»? Кроме того, я правильно вас понимаю — вы хотите видеть только классы, у которых есть либо оценка, либо инструктор обоих классов. Если ни один из них не доступен — класс не должен отображаться?

2. @JuliusTuskenis Извините, это было непонятно. Но да, на оба вопроса.

Ответ №1:

Нет, вы не можете использовать LEFT JOIN Instructor поверх имеющегося у вас запроса, потому что первая таблица (оценка) ограничивает количество записей, которые вы получаете в результате при использовании левых объединений. Вы не можете получить NULL из таблицы оценок в результате, если у вас только левое соединение.

Другие варианты:

Необходимость начинать с оценки ограничивает некоторые наиболее очевидные варианты, но я все еще могу придумать два:

  1. Использование right join для присоединения к классу, а затем присоединение к инструктору. Таким образом, мне нужно отфильтровать классы без инструкторов и оценок в части WHERE:
 select 
  Class.ID,
  Class.Class,
  Grade.AverageGrade,
  Instructor.Instructor
from 
  Grade
  right join Class on Grade.ClassID = Class.ID
  left join Instructor on Class.ID = Instructor.Class
where 
  Grade.AverageGrade is not null
  or instructor.Instructor is not null
 
  1. Использование полного объединения grade и instructor возвращает нужные мне записи, поэтому позже фильтрация не требуется, но класс должен быть объединен с использованием идентификатора из grade или instructor, поскольку один из них может быть нулевым.
 select 
  Class.ID,
  Class.Class,
  Grade.AverageGrade,
  Instructor.Instructor
from 
  Grade
  full join Instructor on Grade.ClassID = Instructor.Class
  join Class on coalesce(Grade.ClassID, Instructor.class) = Class.ID
 

Они оба возвращают один и тот же результат.

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

1. Большое спасибо! Я использовал опцию полного объединения. Хотя кажется, что когда я добавил условие для инструктора, например, во время полного объединения full join Instructor on Grade.ClassID = Instructor.Class and Instructor.ID < 5 , <5 условие не сработало. Он по-прежнему полностью объединяет всех инструкторов, независимо от того, какой идентификатор. Мне пришлось добавить это условие в предложение where . Или при полном объединении я полностью присоединился select * from Instructor where Instructor.ID < 5 . Оба работают, но просто любопытно, почему я не могу использовать его в условии полного соединения.

2. @cxc таблица инструктора, как вы определили в вопросе, не имеет идентификатора. Это новый столбец или вы имеете в виду инструктора. Класс? В любом случае — чтобы ответить на ваш вопрос, условия полного объединения описывают, как будут объединены записи из обеих таблиц. Если условие ложно — записи по-прежнему отображаются в результате с нулевыми значениями в других полях таблицы.