Правое внешнее соединение

Язык запросов

Синтаксис и применение Правое внешнее соединение в платформе 1С:Предприятие. Описание и примеры кода.

Полное описание, параметры и ограничения

Правое внешнее соединение

ПРАВОЕ [ВНЕШНЕЕ] СОЕДИНЕНИЕ означает, что в результат запроса надо включить комбинации записей из обеих исходных таблиц, которые соответствуют указанному условию. Кроме того, в результат запроса надо включить также еще и записи из второго (указанного справа от слова СОЕДИНЕНИЕ) источника, для которых не найдено соответствующих условию записей из первого источника.

Таким образом, в результат запроса будут включены все записи из второго источника; они будут соединены с записями из первого источника при выполнении указанного условия. Строки результата запроса, для которых не найдено соответствующих условию записей из первого источника, будут содержать NULL в полях, формируемых на основании записей из этого источника.

Ключевое слова ВНЕШНЕЕ можно не указывать вообще, оно повышает наглядность и удобочитаемость текста запроса.

Пример:

// В отчет необходимо вывести все банки, а для тех,
// кто является также и контрагентом – указать ссылку на контрагента.

ВЫБРАТЬ
Контрагенты.Ссылка КАК Контрагент,
Банки.Ссылка КАК Банк

ИЗ
Справочник.Контрагенты КАК Контрагенты

ПРАВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ
Справочник.Банки КАК Банки

ПО
Контрагенты.Наименование = Банки.Наименование

Результат запроса:

Контрагент

Банк

NULL

АКБ ИвестБанк

АКБ ПромСтройБанк

АКБ ПромСтройБанк

См. также:
Внутреннее соединение
Левое внешнее соединение
Полное внешнее соединение

Практические примеры

Сверить два своих списка: внутреннее, левое, правое и полное соединение

Слева коды 1,2,3; справа 1,2,4. В пяти законченных запросах сравниваются совпадения, отсутствующие стороны и ошибка соединения без условия: вместо 2 пар получается 9.

Где и как запускать

Полный серверный общий модуль учебной базы 8.5.1.1343. Свои значения и приватные временные таблицы, без рабочих источников, внешних файлов и сети; здесь не запускался.

Подготовка

  1. В отдельной учебной базе 8.5.1.1343 создайте общий модуль УчебныйЯзык: Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь. Клиентские и внешнее соединение отключены; ПовторноеИспользованиеВозвращаемыхЗначений=НеИспользовать.

  2. Вставьте весь приведённый текст в этот общий модуль. ВыполнитьПример — экспортная точка входа; остальные процедуры и функции располагаются рядом, а не внутри неё.

  3. В своей внешней учебной обработке создайте управляемую форму, команду Выполнить и кнопку. Клиентский обработчик Выполнить(Команда) вызывает свою процедуру ВыполнитьНаСервере(); она имеет директиву &НаСервереБезКонтекста и одну строку УчебныйЯзык.ВыполнитьПример();. Это серверный вызов общего модуля, а не разрешение клиенту прямо обращаться к серверной библиотеке.

  4. Все товары, количества и строки придуманы в этом модуле. Запись документов, подключение к чужой базе, файлы, сеть и печать не используются. В рабочие общие модули текст не вставляйте.

  5. HTML только показывает BSL. Код в 1С не запускался; перечисленные результаты и отрицательные опыты проверяйте самостоятельно в собственном стенде.

  6. Два списка полностью создаются внутри модуля. Подключения к документам, регистрам и справочникам конфигурации не нужны.

  7. Функция СоздатьСвоюТаблицу получает только три заданных числовых кода от собственного модуля; массив создаётся пустым и заполняется Добавить, не конструктором размеров.

  8. Нужен серверный контекст по общей подготовке. Две временные таблицы создаются в новом собственном МенеджерВременныхТаблиц; его не берут из рабочего отчёта.

Процедура ВыполнитьПример() Экспорт
    Левые = СоздатьСвоюТаблицу(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. Создать две собственные типизированные таблицы: 1,2,3 и 1,2,4. Все коды положительны, каждый ключ встречается один раз.

  2. Передать таблицы двумя параметрами и выполнить пакет создания двух временных таблиц своего менеджера.

  3. Внутреннее соединение ПО равенству ключей даёт только 1:1 и 2:2, всего две пары.

  4. Левое сохраняет весь левый список: добавляется 3:NULL. Правое сохраняет правый: добавляется NULL:4.

  5. Полное сохраняет несовпавшие строки обеих сторон, всего четыре пары. NULL в полях означает отсутствие подходящей строки другой стороны.

  6. Для отображения заменить NULL на зарезервированный 0, но отдельно сохранить флаги ЕСТЬ NULL до замены. Настоящего кода 0 в собственных источниках нет.

  7. Две таблицы через запятую без условия дают все девять комбинаций 3×3, не только совпадения. Это отдельный контроль распространённой ошибки.

  8. Явно сортировать по двум выведенным кодам, затем проверить полный состав пар, их количество и обе стороны NULL.

  9. Закрыть свой менеджер временных таблиц при успехе и при исключении; рабочие таблицы и файлы не затрагиваются.

Как проверить результат

  1. Получены пять проверенных составов пар: 2,3,3,4 и 9 строк.

  2. У левого соединения одна отсутствующая правая сторона; у правого одна левая; у полного по одной с каждой стороны.

  3. Ожидаемые строки пар заданы полностью и проверены, а не только количество строк.

  4. Сортировка определена явно; менеджер закрыт в обоих исходах, записи конфигурации не менялись.

Ожидаемый результат

Пять видов сочетания собственных источников разобраны на одном понятном образце с проверками состава и NULL.

На что обратить внимание

  1. ЛЕВОЕ/ПРАВОЕ определяют расположение источников в тексте, не направление стрелки в произвольной картинке.

  2. NULL не является реальным нулевым кодом. Здесь 0 только отображаемый маркер; флаги отсутствия вычислены отдельно.

  3. Количество 2/3/3/4 верно для этих уникальных ключей. Повторяющиеся ключи размножают совпавшие пары; соединение само по себе не удаляет дубли.

  4. Отбор по полю правого источника в ГДЕ после левого соединения может исключить строки NULL. Этот урок не подменяет ПО таким отбором.

  5. У собственного менеджера временные таблицы приватны этому опыту; не передавайте сюда менеджер чужого рабочего запроса.

  6. HTML BSL не исполняет; проверки Python моделируют свой образец, но не подтверждают выполнение в 1С.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.