Синтаксис и применение Правое внешнее соединение в платформе 1С:Предприятие. Описание и примеры кода.
Полное описание, параметры и ограничения
Правое внешнее соединение
ПРАВОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ означает, что в результат запроса надо включить комбинации записей из обеих исходных таблиц, которые соответствуют указанному условию. Кроме того, в результат запроса надо включить также еще и записи из второго (указанного справа от слова СОЕДИНЕНИЕ) источника, для которых не найдено соответствующих условию записей из первого источника.
Таким образом, в результат запроса будут включены все записи из второго источника; они будут соединены с записями из первого источника при выполнении указанного условия. Строки результата запроса, для которых не найдено соответствующих условию записей из первого источника, будут содержать NULL в полях, формируемых на основании записей из этого источника.
Ключевое слова ВНЕШНЕЕ можно не указывать вообще, оно повышает наглядность и удобочитаемость текста запроса.
Пример:
// В отчет необходимо вывести все банки, а для тех,
// кто является также и контрагентом – указать ссылку на контрагента.
ВЫБРАТЬ
Контрагенты.Ссылка КАК Контрагент,
Банки.Ссылка КАК Банк
ИЗ
Справочник.Контрагенты КАК Контрагенты
ПРАВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ
Справочник.Банки КАК Банки
ПО
Контрагенты.Наименование = Банки.Наименование
Результат запроса:
Контрагент
Банк
NULL
АКБ ИвестБанк
АКБ ПромСтройБанк
АКБ ПромСтройБанк
См. также:
Внутреннее соединение
Левое внешнее соединение
Полное внешнее соединение
Практические примеры
Сверить два своих списка: внутреннее, левое, правое и полное соединение
Слева коды 1,2,3; справа 1,2,4. В пяти законченных запросах сравниваются совпадения, отсутствующие стороны и ошибка соединения без условия: вместо 2 пар получается 9.
Где и как запускать
Полный серверный общий модуль учебной базы 8.5.1.1343. Свои значения и приватные временные таблицы, без рабочих источников, внешних файлов и сети; здесь не запускался.
Подготовка
В отдельной учебной базе 8.5.1.1343 создайте общий модуль УчебныйЯзык: Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь. Клиентские и внешнее соединение отключены; ПовторноеИспользованиеВозвращаемыхЗначений=НеИспользовать.
Вставьте весь приведённый текст в этот общий модуль. ВыполнитьПример — экспортная точка входа; остальные процедуры и функции располагаются рядом, а не внутри неё.
В своей внешней учебной обработке создайте управляемую форму, команду Выполнить и кнопку. Клиентский обработчик Выполнить(Команда) вызывает свою процедуру ВыполнитьНаСервере(); она имеет директиву &НаСервереБезКонтекста и одну строку УчебныйЯзык.ВыполнитьПример();. Это серверный вызов общего модуля, а не разрешение клиенту прямо обращаться к серверной библиотеке.
Все товары, количества и строки придуманы в этом модуле. Запись документов, подключение к чужой базе, файлы, сеть и печать не используются. В рабочие общие модули текст не вставляйте.
HTML только показывает BSL. Код в 1С не запускался; перечисленные результаты и отрицательные опыты проверяйте самостоятельно в собственном стенде.
Два списка полностью создаются внутри модуля. Подключения к документам, регистрам и справочникам конфигурации не нужны.
Функция СоздатьСвоюТаблицу получает только три заданных числовых кода от собственного модуля; массив создаётся пустым и заполняется Добавить, не конструктором размеров.
Нужен серверный контекст по общей подготовке. Две временные таблицы создаются в новом собственном МенеджерВременныхТаблиц; его не берут из рабочего отчёта.
Процедура ВыполнитьПример() Экспорт
Левые = СоздатьСвоюТаблицу(1, 2, 3);
Правые = СоздатьСвоюТаблицу(1, 2, 4);
Если Левые.Количество() <> 3 Или Правые.Количество() <> 3 Тогда
ВызватьИсключение "Изменился собственный образец двух списков";
КонецЕсли;
Менеджер = Новый МенеджерВременныхТаблиц;
Попытка
Создание = Новый Запрос;
Создание.МенеджерВременныхТаблиц = Менеджер;
Создание.Текст = "ВЫБРАТЬ Левые.Код КАК Код
|ПОМЕСТИТЬ ВТСобственныеЛевые
|ИЗ &Левые КАК Левые;
|
|ВЫБРАТЬ Правые.Код КАК Код
|ПОМЕСТИТЬ ВТСобственныеПравые
|ИЗ &Правые КАК Правые";
Создание.УстановитьПараметр("Левые", Левые);
Создание.УстановитьПараметр("Правые", Правые);
Создание.ВыполнитьПакет();
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Менеджер;
Запрос.Текст = "ВЫБРАТЬ
| ЕСТЬNULL(Левые.Код, 0) КАК КодСлева,
| ЕСТЬNULL(Правые.Код, 0) КАК КодСправа,
| ВЫБОР КОГДА Левые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСлева,
| ВЫБОР КОГДА Правые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСправа
|ИЗ ВТСобственныеЛевые КАК Левые
|ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТСобственныеПравые КАК Правые
|ПО Левые.Код = Правые.Код
|УПОРЯДОЧИТЬ ПО КодСлева, КодСправа";
Результат = Запрос.Выполнить().Выгрузить();
Сообщить("Внутреннее");
ПроверитьСвоиПары(Результат, 2, "1:1|2:2|", 0, 0);
Запрос.Текст = "ВЫБРАТЬ
| ЕСТЬNULL(Левые.Код, 0) КАК КодСлева,
| ЕСТЬNULL(Правые.Код, 0) КАК КодСправа,
| ВЫБОР КОГДА Левые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСлева,
| ВЫБОР КОГДА Правые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСправа
|ИЗ ВТСобственныеЛевые КАК Левые
|ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ ВТСобственныеПравые КАК Правые
|ПО Левые.Код = Правые.Код
|УПОРЯДОЧИТЬ ПО КодСлева, КодСправа";
Результат = Запрос.Выполнить().Выгрузить();
Сообщить("Левое");
ПроверитьСвоиПары(Результат, 3, "1:1|2:2|3:0|", 0, 1);
Запрос.Текст = "ВЫБРАТЬ
| ЕСТЬNULL(Левые.Код, 0) КАК КодСлева,
| ЕСТЬNULL(Правые.Код, 0) КАК КодСправа,
| ВЫБОР КОГДА Левые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСлева,
| ВЫБОР КОГДА Правые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСправа
|ИЗ ВТСобственныеЛевые КАК Левые
|ПРАВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ ВТСобственныеПравые КАК Правые
|ПО Левые.Код = Правые.Код
|УПОРЯДОЧИТЬ ПО КодСлева, КодСправа";
Результат = Запрос.Выполнить().Выгрузить();
Сообщить("Правое");
ПроверитьСвоиПары(Результат, 3, "0:4|1:1|2:2|", 1, 0);
Запрос.Текст = "ВЫБРАТЬ
| ЕСТЬNULL(Левые.Код, 0) КАК КодСлева,
| ЕСТЬNULL(Правые.Код, 0) КАК КодСправа,
| ВЫБОР КОГДА Левые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСлева,
| ВЫБОР КОГДА Правые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСправа
|ИЗ ВТСобственныеЛевые КАК Левые
|ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ ВТСобственныеПравые КАК Правые
|ПО Левые.Код = Правые.Код
|УПОРЯДОЧИТЬ ПО КодСлева, КодСправа";
Результат = Запрос.Выполнить().Выгрузить();
Сообщить("Полное");
ПроверитьСвоиПары(Результат, 4, "0:4|1:1|2:2|3:0|", 1, 1);
Запрос.Текст = "ВЫБРАТЬ
| ЕСТЬNULL(Левые.Код, 0) КАК КодСлева,
| ЕСТЬNULL(Правые.Код, 0) КАК КодСправа,
| ВЫБОР КОГДА Левые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСлева,
| ВЫБОР КОГДА Правые.Код ЕСТЬ NULL ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК НетСправа
|ИЗ ВТСобственныеЛевые КАК Левые, ВТСобственныеПравые КАК Правые
|УПОРЯДОЧИТЬ ПО КодСлева, КодСправа";
Результат = Запрос.Выполнить().Выгрузить();
Сообщить("Без условия: декартово произведение");
ПроверитьСвоиПары(Результат, 9, "1:1|1:2|1:4|2:1|2:2|2:4|3:1|3:2|3:4|", 0, 0);
Исключение
Менеджер.Закрыть();
ВызватьИсключение;
КонецПопытки;
Менеджер.Закрыть();
КонецПроцедуры
Функция СоздатьСвоюТаблицу(Первый, Второй, Третий)
Источник = Новый ТаблицаЗначений;
Источник.Колонки.Добавить("Код", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(5, 0, ДопустимыйЗнак.Неотрицательный)));
Коды = Новый Массив;
Коды.Добавить(Первый);
Коды.Добавить(Второй);
Коды.Добавить(Третий);
Для Каждого КодОбразца Из Коды Цикл
Если КодОбразца <= 0 Тогда
ВызватьИсключение "Ноль зарезервирован для отображения NULL, свои коды положительны";
КонецЕсли;
НоваяСтрока = Источник.Добавить();
НоваяСтрока.Код = КодОбразца;
КонецЦикла;
Возврат Источник;
КонецФункции
Процедура ПроверитьСвоиПары(Таблица, ОжидаемоеКоличество, ОжидаемыеПары, ОжидалосьБезЛевой, ОжидалосьБезПравой)
Если Таблица.Количество() <> ОжидаемоеКоличество Тогда
ВызватьИсключение "Неверное количество собственных пар";
КонецЕсли;
Пары = "";
БезЛевой = 0;
БезПравой = 0;
Для Каждого СтрокаРезультата Из Таблица Цикл
Пары = Пары + Строка(СтрокаРезультата.КодСлева) + ":" + Строка(СтрокаРезультата.КодСправа) + "|";
Если СтрокаРезультата.НетСлева Тогда
БезЛевой = БезЛевой + 1;
КонецЕсли;
Если СтрокаРезультата.НетСправа Тогда
БезПравой = БезПравой + 1;
КонецЕсли;
КонецЦикла;
Если Пары <> ОжидаемыеПары Или БезЛевой <> ОжидалосьБезЛевой Или БезПравой <> ОжидалосьБезПравой Тогда
ВызватьИсключение "Пары или стороны NULL не соответствуют своему образцу";
КонецЕсли;
Сообщить("Проверены пары: " + Пары);
Сообщить("Без левой: " + Строка(БезЛевой) + "; без правой: " + Строка(БезПравой));
КонецПроцедурыРазбор по шагам
Создать две собственные типизированные таблицы: 1,2,3 и 1,2,4. Все коды положительны, каждый ключ встречается один раз.
Передать таблицы двумя параметрами и выполнить пакет создания двух временных таблиц своего менеджера.
Внутреннее соединение ПО равенству ключей даёт только 1:1 и 2:2, всего две пары.
Левое сохраняет весь левый список: добавляется 3:NULL. Правое сохраняет правый: добавляется NULL:4.
Полное сохраняет несовпавшие строки обеих сторон, всего четыре пары. NULL в полях означает отсутствие подходящей строки другой стороны.
Для отображения заменить NULL на зарезервированный 0, но отдельно сохранить флаги ЕСТЬ NULL до замены. Настоящего кода 0 в собственных источниках нет.
Две таблицы через запятую без условия дают все девять комбинаций 3×3, не только совпадения. Это отдельный контроль распространённой ошибки.
Явно сортировать по двум выведенным кодам, затем проверить полный состав пар, их количество и обе стороны NULL.
Закрыть свой менеджер временных таблиц при успехе и при исключении; рабочие таблицы и файлы не затрагиваются.
Как проверить результат
Получены пять проверенных составов пар: 2,3,3,4 и 9 строк.
У левого соединения одна отсутствующая правая сторона; у правого одна левая; у полного по одной с каждой стороны.
Ожидаемые строки пар заданы полностью и проверены, а не только количество строк.
Сортировка определена явно; менеджер закрыт в обоих исходах, записи конфигурации не менялись.
Ожидаемый результат
Пять видов сочетания собственных источников разобраны на одном понятном образце с проверками состава и NULL.
На что обратить внимание
ЛЕВОЕ/ПРАВОЕ определяют расположение источников в тексте, не направление стрелки в произвольной картинке.
NULL не является реальным нулевым кодом. Здесь 0 только отображаемый маркер; флаги отсутствия вычислены отдельно.
Количество 2/3/3/4 верно для этих уникальных ключей. Повторяющиеся ключи размножают совпавшие пары; соединение само по себе не удаляет дубли.
Отбор по полю правого источника в ГДЕ после левого соединения может исключить строки NULL. Этот урок не подменяет ПО таким отбором.
У собственного менеджера временные таблицы приватны этому опыту; не передавайте сюда менеджер чужого рабочего запроса.
HTML BSL не исполняет; проверки Python моделируют свой образец, но не подтверждают выполнение в 1С.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.