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