Почему при левом соединении в запросе 1С выводятся не все записи и как это исправить

Программист 1С:Комплексная автоматизация Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке отчетов в системе 1С:Предприятие 8, особенно в таких сложных конфигурациях как Комплексная автоматизация 2 или ERP, программисты часто сталкиваются с ситуацией, когда ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) ведет себя непредсказуемо. Вместо того чтобы вывести все записи из левой таблицы и дополнить их данными из правой, запрос возвращает только те строки, которые есть в обеих таблицах. Фактически левое соединение превращается во внутреннее.

Разберем детально, почему это происходит, проанализируем типичные ошибки в тексте запроса и выясним, как правильно связать данные, чтобы не потерять важные записи.

Причина №1: Фильтрация правой таблицы в секции ГДЕ

Это самая распространенная ошибка. Рассмотрим ситуацию на примере запроса из обсуждения. Программист соединяет временную таблицу Продукция со справочником ПартииПроизводства. У него есть условие в конце запроса:


ГДЕ
    НЕ ПартииПроизводства.ПометкаУдаления

Проанализируем механизм выполнения: когда 1С выполняет левое соединение, для тех записей левой таблицы, которым не нашлось соответствия в правой, все поля правой таблицы заполняются значением NULL. Затем вступает в силу секция ГДЕ. Проверка НЕ NULL (или любая другая операция сравнения с NULL) дает результат "Ложь" или "Неизвестно". В итоге все записи, для которых партия не была найдена, отсекаются этим фильтром.

Как исправить: все условия, накладываемые на правую (присоединяемую) таблицу, должны быть перенесены непосредственно в условие связи ПО. Рассмотрим правильный вариант:


ИЗ
    Продукция КАК Продукция
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПартииПроизводства КАК ПартииПроизводства
        ПО Продукция.Номенклатура = ПартииПроизводства.Номенклатура
            И Продукция.ХарактеристикаНоменклатуры = ПартииПроизводства.Характеристика
            И (НЕ ПартииПроизводства.ПометкаУдаления) // Условие внутри связи!

Причина №2: Обращение через точку в условиях связи

В тексте запроса часто встречается конструкция Продукция.ДокументПроизводства.ГруппировкаЗатрат. Использование обращения "через точку" в условиях связи ПО — это плохая практика по нескольким причинам:

  1. Неявные соединения: Платформа 1С при выполнении такого запроса создает дополнительное неявное ВНУТРЕННЕЕ СОЕДИНЕНИЕ с таблицей документа. Если в поле ДокументПроизводства окажется пустая ссылка или объект другого типа, вся строка будет исключена из результата еще до того, как сработает левое соединение.
  2. Производительность: Такие обращения создают избыточную нагрузку на СУБД, так как оптимизатору сложнее построить эффективный план выполнения.

Решение: вынесем все необходимые поля во временную таблицу (ВТ) заранее. Сначала подготовим данные, а затем будем их соединять.

Рассмотрим, как должна выглядеть структура первой ВТ Продукция:


ВЫБРАТЬ
    ВыходныеИзделия.Ссылка КАК ДокументПроизводства,
    ВыходныеИзделия.Ссылка.ГруппировкаЗатрат КАК ГруппировкаЗатрат, // Выбираем поле заранее
    ВыходныеИзделия.Номенклатура КАК Номенклатура,
    ВыходныеИзделия.Характеристика КАК Характеристика
ПОМЕСТИТЬ Продукция
ИЗ
    Документ.ПроизводствоБезЗаказа.ВыходныеИзделия КАК ВыходныеИзделия

Теперь во втором запросе мы сможем сравнивать Продукция.ГруппировкаЗатрат напрямую, без обращений через точку.

Причина №3: Проблема соответствия типов данных

В Комплексной автоматизации 2 поле Документ в справочнике ПартииПроизводства может иметь составной тип данных. Если в левой таблице тип поля ДокументПроизводства определен нечетко (например, если это результат объединения разных таблиц), СУБД может некорректно сопоставлять ссылки.

Выясним, как обеспечить жесткую типизацию. Для этого в первой ВТ полезно использовать функцию ВЫРАЗИТЬ. Это гарантирует, что при соединении система будет сравнивать значения одного и того же типа, что критически важно для корректной работы индексов.


ВЫБРАТЬ
    ВЫРАЗИТЬ(ВыходныеИзделия.Ссылка КАК Документ.ПроизводствоБезЗаказа) КАК ДокументПроизводства,
    ...

Причина №4: Пустые значения и NULL

Еще одна неочевидная причина — разница между "Пустой ссылкой" и значением NULL. В 1С это разные понятия.

Если в ВТ Продукция поле Характеристика заполнено значением Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка, а в справочнике ПартииПроизводства для соответствующей записи в этом поле стоит NULL (или наоборот), то условие Продукция.Характеристика = ПартииПроизводства.Характеристика не выполнится.

Проанализируем ситуацию: в SQL сравнение NULL = NULL не дает истины. Чтобы избежать этой ловушки, рекомендуется:

Итоговый правильный алгоритм сборки запроса

Для того чтобы ваш запрос гарантированно возвращал все записи из левой таблицы, придерживайтесь следующей последовательности действий:

  1. Подготовка данных: Создайте временную таблицу для "левой" части. Выберите в нее все поля, которые потребуются для связи (Номенклатура, Характеристика, Склад и т.д.).
  2. Отказ от точек: Все реквизиты, к которым нужно обращаться "через точку" от ссылки (например, Документ.ГруппировкаЗатрат), выберите в отдельные колонки этой же ВТ.
  3. Чистое соединение: В основном запросе используйте ЛЕВОЕ СОЕДИНЕНИЕ.
  4. Фильтры в ПО: Если вам нужно отсечь помеченные на удаление записи в правой таблице или добавить любые другие ограничения на правую таблицу, пишите их только внутри секции ПО.
  5. Контроль типов: Если поля связи имеют составной тип, используйте ВЫРАЗИТЬ для приведения к конкретному типу.

Соблюдение этих правил исключит "исчезновение" записей и сделает ваши отчеты в 1С:Комплексная автоматизация точными и надежными. Помните, что любая проверка поля правой таблицы в секции ГДЕ автоматически превращает ваше соединение во внутреннее, удаляя из результата все строки, для которых данные в правой таблице отсутствуют.

← На главную