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