При разработке отчетов в системе 1С:Предприятие 8, особенно в таких сложных конфигурациях как Комплексная автоматизация 2 или ERP, программисты часто сталкиваются с ситуацией, когда ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) ведет себя непредсказуемо. Вместо того чтобы вывести все записи из левой таблицы и дополнить их данными из правой, запрос возвращает только те строки, которые есть в обеих таблицах. Фактически левое соединение превращается во внутреннее.
Разберем детально, почему это происходит, проанализируем типичные ошибки в тексте запроса и выясним, как правильно связать данные, чтобы не потерять важные записи.
Это самая распространенная ошибка. Рассмотрим ситуацию на примере запроса из обсуждения. Программист соединяет временную таблицу Продукция со справочником ПартииПроизводства. У него есть условие в конце запроса:
ГДЕ
НЕ ПартииПроизводства.ПометкаУдаления
Проанализируем механизм выполнения: когда 1С выполняет левое соединение, для тех записей левой таблицы, которым не нашлось соответствия в правой, все поля правой таблицы заполняются значением NULL. Затем вступает в силу секция ГДЕ. Проверка НЕ NULL (или любая другая операция сравнения с NULL) дает результат "Ложь" или "Неизвестно". В итоге все записи, для которых партия не была найдена, отсекаются этим фильтром.
Как исправить: все условия, накладываемые на правую (присоединяемую) таблицу, должны быть перенесены непосредственно в условие связи ПО. Рассмотрим правильный вариант:
ИЗ
Продукция КАК Продукция
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПартииПроизводства КАК ПартииПроизводства
ПО Продукция.Номенклатура = ПартииПроизводства.Номенклатура
И Продукция.ХарактеристикаНоменклатуры = ПартииПроизводства.Характеристика
И (НЕ ПартииПроизводства.ПометкаУдаления) // Условие внутри связи!
В тексте запроса часто встречается конструкция Продукция.ДокументПроизводства.ГруппировкаЗатрат. Использование обращения "через точку" в условиях связи ПО — это плохая практика по нескольким причинам:
ВНУТРЕННЕЕ СОЕДИНЕНИЕ с таблицей документа. Если в поле ДокументПроизводства окажется пустая ссылка или объект другого типа, вся строка будет исключена из результата еще до того, как сработает левое соединение.Решение: вынесем все необходимые поля во временную таблицу (ВТ) заранее. Сначала подготовим данные, а затем будем их соединять.
Рассмотрим, как должна выглядеть структура первой ВТ Продукция:
ВЫБРАТЬ
ВыходныеИзделия.Ссылка КАК ДокументПроизводства,
ВыходныеИзделия.Ссылка.ГруппировкаЗатрат КАК ГруппировкаЗатрат, // Выбираем поле заранее
ВыходныеИзделия.Номенклатура КАК Номенклатура,
ВыходныеИзделия.Характеристика КАК Характеристика
ПОМЕСТИТЬ Продукция
ИЗ
Документ.ПроизводствоБезЗаказа.ВыходныеИзделия КАК ВыходныеИзделия
Теперь во втором запросе мы сможем сравнивать Продукция.ГруппировкаЗатрат напрямую, без обращений через точку.
В Комплексной автоматизации 2 поле Документ в справочнике ПартииПроизводства может иметь составной тип данных. Если в левой таблице тип поля ДокументПроизводства определен нечетко (например, если это результат объединения разных таблиц), СУБД может некорректно сопоставлять ссылки.
Выясним, как обеспечить жесткую типизацию. Для этого в первой ВТ полезно использовать функцию ВЫРАЗИТЬ. Это гарантирует, что при соединении система будет сравнивать значения одного и того же типа, что критически важно для корректной работы индексов.
ВЫБРАТЬ
ВЫРАЗИТЬ(ВыходныеИзделия.Ссылка КАК Документ.ПроизводствоБезЗаказа) КАК ДокументПроизводства,
...
Еще одна неочевидная причина — разница между "Пустой ссылкой" и значением NULL. В 1С это разные понятия.
Если в ВТ Продукция поле Характеристика заполнено значением Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка, а в справочнике ПартииПроизводства для соответствующей записи в этом поле стоит NULL (или наоборот), то условие Продукция.Характеристика = ПартииПроизводства.Характеристика не выполнится.
Проанализируем ситуацию: в SQL сравнение NULL = NULL не дает истины. Чтобы избежать этой ловушки, рекомендуется:
NULL перед соединением.ЕСТЬNULL(Поле, ЗначениеЗамены), чтобы привести неопределенные значения к единому виду (например, к пустой ссылке).Для того чтобы ваш запрос гарантированно возвращал все записи из левой таблицы, придерживайтесь следующей последовательности действий:
Номенклатура, Характеристика, Склад и т.д.).Документ.ГруппировкаЗатрат), выберите в отдельные колонки этой же ВТ.ЛЕВОЕ СОЕДИНЕНИЕ.ПО.ВЫРАЗИТЬ для приведения к конкретному типу.Соблюдение этих правил исключит "исчезновение" записей и сделает ваши отчеты в 1С:Комплексная автоматизация точными и надежными. Помните, что любая проверка поля правой таблицы в секции ГДЕ автоматически превращает ваше соединение во внутреннее, удаляя из результата все строки, для которых данные в правой таблице отсутствуют.