Использование внутренних соединений

Завершено

Наиболее частым типом оператора JOIN в запросах T-SQL является INNER JOIN. Внутренние соединения позволяют решать многие распространенные бизнес-задачи, особенно в средах баз данных с высоким уровнем нормализации. Для получения данных, хранящихся в нескольких таблицах, часто приходится объединять эти таблицы с помощью запросов INNER JOIN. INNER JOIN начинает этап логической обработки с получения декартового произведения, которое затем фильтруется для удаления всех строк, не соответствующих предикату.

Обработка запроса INNER JOIN

Рассмотрим этапы логической обработки запроса JOIN в SQL Server. В приведенном ниже гипотетическом примере для ясности добавлены номера строк:

1) SELECT emp.FirstName, ord.Amount
2) FROM HR.Employee AS emp 
3) JOIN Sales.SalesOrder AS ord
4)      ON emp.EmployeeID = ord.EmployeeID;

Как вы уже поняли, предложение FROM будет обработано до предложения SELECT. Просмотрим обработку, начиная со строки 2.

  • Предложение FROM указывает таблицу HR.Employee в качестве одной из входных таблиц, присваивая ей псевдоним emp.
  • Оператор JOIN в строке 3 отражает использование INNER JOIN (тип по умолчанию в T-SQL) и указывает Sales.SalesOrder в качестве другой входной таблицы, которая имеет псевдоним ord.
  • SQL Server выполнит логическое декартово соединение этих таблиц и передаст результаты в виде виртуальной таблицы на следующий этап. (Физическая обработка запроса может не выполнять операцию декартового произведения в зависимости от решений оптимизатора. Но может быть полезной, чтобы представить создаваемое декартово произведение.)
  • Используя предложение ON, SQL Server отфильтрует виртуальную таблицу, сохраняя только те строки, в которых значение EmployeeID из таблицы emp соответствует EmployeeID в таблице ord.
  • Оставшиеся строки остаются в виртуальной таблице и передаются на следующий этап в инструкции SELECT. В этом примере виртуальная таблица далее обрабатывается предложением SELECT, и два указанных столбца возвращаются в клиентское приложение.

Результатом выполнения запроса является список сотрудников и их суммы заказов. Сотрудники, не имеющие связанных заказов, были отфильтрованы оператором ON, как и любые заказы с EmployeeID, которые не соответствуют записям в таблице HR.Employee.

Схема Венна с соответствующими элементами наборов Employee и SalesOrder

Синтаксис INNER JOIN

INNER JOIN является заданным по умолчанию типом предложения JOIN, а дополнительное ключевое слово INNER является неявным в предложении JOIN. При смешении и сопоставлении типов соединений может быть полезно явно указать тип соединения, как показано в следующем гипотетическом примере:

SELECT emp.FirstName, ord.Amount
FROM HR.Employee AS emp 
INNER JOIN Sales.SalesOrder AS ord
    ON emp.EmployeeID = ord.EmployeeID;

При написании запросов с использованием внутренних соединений необходимо учитывать следующие рекомендации.

  • Псевдонимы таблиц являются предпочтительными не только для списка SELECT, а также для написания предложения ON.
  • Внутренние соединения могут выполняться для одного соответствующего столбца, например OrderID или нескольких соответствующих атрибутов, таких как сочетание OrderID и ProductID. Соединения, указывающие несколько соответствующих столбцов, называются составными соединениями.
  • Порядок, в котором таблицы перечислены в предложении FROM для INNER JOIN, не имеет значения для оптимизатора SQL Server. По сути, соединения будут обрабатываться слева направо.
  • Используйте ключевое слово JOIN один раз для каждой пары соединяемых таблиц в списке FROM. Для запроса к двум таблицам укажите одно соединение. Для запроса к трем таблицам ключевое слово JOIN будет использоваться дважды — один раз между двумя первыми таблицами и один раз между выходными данными JOIN между двумя первыми таблицами и третьей таблицей.

Примеры INNER JOIN

Следующий гипотетический пример выполняет объединение по одному соответствующему столбцу, связывая ProductModelID в таблице Production.Product с ProductModelID в таблице Production.ProductModel.

SELECT p.ProductID, m.Name AS Model, p.Name AS Product
FROM Production.Product AS p
INNER JOIN Production.ProductModel AS m
    ON p.ProductModelID = m.ProductModelID
ORDER BY p.ProductID;

В следующем примере показано, как можно расширить внутреннее соединение для включения более двух таблиц. Таблица Sales.SalesOrderDetail присоединяется к выходным данным JOIN между Production.Product и Production.ProductModel. Каждый экземпляр JOIN/ON выполняет собственное заполнение и фильтрацию виртуальной выходной таблицы. Оптимизатор запросов SQL Server определяет порядок, в котором будут выполняться операции соединения и фильтрации.

SELECT od.SalesOrderID, m.Name AS Model, p.Name AS ProductName, od.OrderQty
FROM Production.Product AS p
INNER JOIN Production.ProductModel AS m
    ON p.ProductModelID = m.ProductModelID
INNER JOIN Sales.SalesOrderDetail AS od
    ON p.ProductID = od.ProductID
ORDER BY od.SalesOrderID;