При разработке отчетов в 1С:Предприятие 8 часто возникает необходимость вывести данные из нескольких табличных частей одного документа. Казалось бы, ПОЛНОЕ СОЕДИНЕНИЕ — идеальный инструмент для объединения этих данных. Однако на практике разработчики часто сталкиваются с ситуацией, когда данные, существующие в одной табличной части, «исчезают» из выборки, если в другой табличной части соответствующих записей нет. Давайте разберем, почему это происходит и как правильно организовать получение данных.
Основная проблема заключается в использовании секции ГДЕ при работе с соединениями. Когда мы используем ПОЛНОЕ СОЕДИНЕНИЕ, движок запроса объединяет таблицы. Если в одной из них нет записи, соответствующей условию ПО, система подставляет NULL в поля отсутствующей таблицы.
Как только мы добавляем условие в секцию ГДЕ, например Ссылка.Проведен, мы принудительно отсекаем строки, которые не удовлетворяют этому условию. Поскольку NULL не является «истиной», любая проверка с его участием в блоке ГДЕ приводит к тому, что запись просто исключается из итогового результата. В итоге ПОЛНОЕ СОЕДИНЕНИЕ фактически превращается во ВНУТРЕННЕЕ СОЕДИНЕНИЕ, так как все записи, где хотя бы одна таблица пуста, отсеиваются.
Чтобы избежать отсечения строк, можно обернуть условия проверки в функцию ЕСТЬNULL. Мы говорим системе: если значение равно NULL, замени его на «Истину», чтобы фильтр не удалял строку.
Рассмотрим пример правильного написания условий:
ВЫБРАТЬ
ЕСТЬNULL(ПутевойЛистТопливо.Ссылка.Дата, ПутевойЛистМаршрут.Ссылка.Дата) КАК Дата,
СУММА(ПутевойЛистТопливо.Количество) КАК Количество,
СУММА(ПутевойЛистМаршрут.Расстояние) КАК Расстояние
ИЗ Документ.ПутевойЛист.Маршрут КАК ПутевойЛистМаршрут
ПОЛНОЕ СОЕДИНЕНИЕ Документ.ПутевойЛист.Топливо КАК ПутевойЛистТопливо
ПО ПутевойЛистМаршрут.Ссылка = ПутевойЛистТопливо.Ссылка
ГДЕ ЕстьNULL(ПутевойЛистМаршрут.Ссылка.Проведен, Истина)
И ЕстьNULL(ПутевойЛистТопливо.Ссылка.Проведен, Истина)
И ЕстьNULL(ПутевойЛистМаршрут.Ссылка.Дата, &ДатаНач) >= &ДатаНач
Более надежный и читаемый способ — это разделение задачи на этапы. Мы можем поместить данные из каждой табличной части во временные таблицы (ВТ), предварительно отфильтровав их, а затем соединить эти таблицы между собой. Это делает запрос логически понятным и позволяет избежать путаницы с NULL.
Разберем этапы создания такого запроса:
Количество или Расстояние).ЛЕВОЕ или ПОЛНОЕ соединение.
// Шаг 1: Получаем данные по топливу
ВЫБРАТЬ СУММА(Количество) КАК Количество, Ссылка
ПОМЕСТИТЬ вт_Топливо
ИЗ Документ.ПутевойЛист.Топливо
ГДЕ Ссылка.Проведен И Ссылка.Дата МЕЖДУ &ДатаНач И &ДатаКон
СГРУППИРОВАТЬ ПО Ссылка;
// Шаг 2: Получаем данные по маршрутам
ВЫБРАТЬ СУММА(Расстояние) КАК Расстояние, Ссылка
ПОМЕСТИТЬ вт_Маршрут
ИЗ Документ.ПутевойЛист.Маршрут
ГДЕ Ссылка.Проведен И Ссылка.Дата МЕЖДУ &ДатаНач И &ДатаКон
СГРУППИРОВАТЬ ПО Ссылка;
// Шаг 3: Объединяем результаты
ВЫБРАТЬ *
ИЗ вт_Топливо КАК Т
ПОЛНОЕ СОЕДИНЕНИЕ вт_Маршрут КАК М ПО Т.Ссылка = М.Ссылка;
Многие разработчики сталкиваются с тем, что МЕЖДУ (или BETWEEN) «не работает». Важно понимать, что этот оператор — лишь сокращенная форма условий >= и <=. Если поле, по которому идет сравнение, содержит NULL, результат сравнения будет не определен, и строка не попадет в выборку. Поэтому при использовании временных таблиц мы фильтруем данные ДО их соединения, тем самым гарантируя, что NULL не попадет в условия фильтрации.
Чтобы отчеты работали стабильно и быстро:
ПОЛНОЕ СОЕДИНЕНИЕ напрямую с ТЧ, если можно сначала собрать данные в Временные таблицы.ЛЕВОЕ СОЕДИНЕНИЕ, если вы идете от «шапки» документа к его табличным частям. Это самый естественный способ построения запросов в 1С.NULL в результатах запроса при использовании полных соединений, используя функцию ЕСТЬNULL для вывода значимых данных (например, дат или сумм).Применение временных таблиц не только решает проблему «исчезновения» строк, но и существенно упрощает отладку запроса, так как вы можете просмотреть результат выполнения каждой временной таблицы отдельно.