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