Разберем распространенную задачу при разработке отчетов на базе системы компоновки данных (СКД) или обычных запросов в 1С. Очень часто требуется вывести полный список родительских документов (например, заказов или счетов) и привязать к ним подчиненные документы (оплаты, приходы на счет, расходы из кассы). При этом нужно наложить фильтр по дате на подчиненный документ так, чтобы сами родительские документы не исчезали из итоговой выборки, даже если по ним не было оплат в указанном периоде.
Проанализируем ситуацию, с которой часто сталкиваются разработчики. Допустим, мы связываем таблицу документов СчетНаОплату с табличной частью платежного документа ПоступлениеНаСчет.РасшифровкаПлатежа с помощью левого соединения.
Посмотрим на пример запроса, содержащего ошибку в логике отбора:
ВЫБРАТЬ
СчетНаОплату1.Ссылка КАК СчетНаОплату,
РП.Ссылка.Ссылка КАК ПоступлениеНаСчет,
РП.СчетНаОплату.Ссылка КАК СчетНаОплатуСсылка
ИЗ
Документ.СчетНаОплату КАК СчетНаОплату1
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеНаСчет.РасшифровкаПлатежа КАК РП
ПО РП.СчетНаОплату.Ссылка = СчетНаОплату1.Ссылка
ГДЕ
РП.Ссылка.Дата МЕЖДУ &ДатаПриходовФактНачало И &ДатаПриходовФактКонец
Выясним причину, почему такой запрос работает некорректно. Когда мы помещаем условие отбора по дате подчиненного документа РП.Ссылка.Дата в секцию ГДЕ, СУБД применяет фильтр к уже сформированной таблице соединения. Если у счета нет подчиненных платежей или их дата не попадает в интервал, поля таблицы РП принимают значение NULL. Но проверка NULL МЕЖДУ &Дата... И &Дата... дает ложь, и СУБД отсекает всю строку целиком, включая сам родительский счет.
Таким образом, использование секции ГДЕ с полем правой (присоединенной) таблицы фактически превращает ЛЕВОЕ СОЕДИНЕНИЕ во ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN).
Чтобы сохранить принцип левого соединения (выводить все счета, а подчиненные платежи выводить только в том случае, если они соответствуют периоду), необходимо перенести условие фильтрации из секции ГДЕ непосредственно в секцию соединения ПО.
Рассмотрим правильный вариант построения запроса:
ВЫБРАТЬ
СчетНаОплату1.Ссылка КАК СчетНаОплату,
РП.Ссылка.Ссылка КАК ПоступлениеНаСчет,
РП.СчетНаОплату.Ссылка КАК СчетНаОплатуСсылка
ИЗ
Документ.СчетНаОплату КАК СчетНаОплату1
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПоступлениеНаСчет.РасшифровкаПлатежа КАК РП
ПО (РП.СчетНаОплату.Ссылка = СчетНаОплату1.Ссылка)
И (РП.Ссылка.Дата МЕЖДУ &ДатаПриходовФактНачало И &ДатаПриходовФактКонец)
Разберем по шагам, как работает этот запрос:
Документ.СчетНаОплату.РасшифровкаПлатежа, которая удовлетворяет одновременно двум условиям: совпадение ссылки на счет и попадание даты документа оплаты в заданный период.NULL.Если отчет разрабатывается в Системе компоновки данных, мы можем использовать дополнительные механизмы платформы 1С для управления гибкими отборами:
НаборДанных1, а платежи — в НаборДанных2. На вкладке «Связи наборов данных» настраиваем связь по ссылке. В этом случае, если пользователь установит отбор по дате в настройках СКД на поле второго набора данных, СКД автоматически применит внутреннюю связь и отфильтрует заказы. Если отбор отключен — связи останутся левыми.
{ГДЕ
РП.Ссылка.Дата МЕЖДУ &ДатаПриходовФактНачало И &ДатаПриходовФактКонец}