При разработке отчетов в системе «1С:Предприятие» программисты часто сталкиваются с неочевидным поведением виртуальных таблиц оборотов. Типичная ситуация: за выбранный период по определенному товару были движения, например, приход на сумму +5 000 рублей и последующий возврат или сторно на сумму -5 000 рублей. Логически суммарный оборот за период равен нулю. Однако при попытке вывести этот товар в отчет с помощью виртуальной таблицы РегистрБухгалтерии.Хозрасчетный.Обороты строка с этим товаром просто исчезает из результата запроса. Возникает резонный вопрос: как заставить систему вывести товар с итоговым нулевым оборотом?
В этой статье мы подробно разберем, почему так происходит на уровне СУБД, проанализируем поведение виртуальных таблиц 1С и рассмотрим три надежных практических способа решения этой проблемы с примерами кода.
Для того чтобы понять, почему строка с товаром пропадает, нам необходимо заглянуть «под капот» платформы 1С и посмотреть, как она взаимодействует с сервером баз данных (будь то MS SQL Server, PostgreSQL или другая СУБД). Виртуальные таблицы не существуют в базе данных физически — они формируются динамически в момент выполнения запроса.
Когда мы обращаемся к виртуальной таблице РегистрБухгалтерии.Хозрасчетный.Обороты с периодичностью Период (или вообще без указания периодичности), платформа транслирует наш запрос в SQL-запрос с группировкой по аналитике (субконто) и периодам. На стороне СУБД это выглядит как использование конструкции GROUP BY.
С целью оптимизации производительности, уменьшения сетевого трафика между сервером приложений 1С и СУБД, а также для исключения пустых строк платформа 1С автоматически накладывает условие фильтрации на сгруппированные данные. В SQL-запросе это реализуется с помощью конструкции HAVING. Платформа проверяет, чтобы хотя бы один из суммируемых числовых ресурсов (дебетовый оборот, кредитовый оборот или общий оборот) не был равен нулю. Если в результате сложения +5 и -5 по всем ресурсам получается чистый ноль, СУБД просто отбрасывает эту строку. Она физически не передается на сервер приложений 1С, и мы получаем пустой результат запроса.
Это наиболее изящный, производительный и правильный с точки зрения архитектуры 1С способ решения проблемы. Суть метода заключается в том, чтобы разбить получение данных на два этапа с использованием временных таблиц в одном пакете запроса.
Рассмотрим этот алгоритм по шагам:
Периодичность в значение Запись (или Регистратор). В этом случае СУБД не будет группировать движения разных документов в одну строку, так как они относятся к разным записям регистра. Строки с положительными и отрицательными оборотами будут выбраны как отдельные записи и не схлопнутся. Полученный результат мы сохраняем во временную таблицу.СГРУППИРОВАТЬ ПО по нужной аналитике (например, по номенклатуре). На этом этапе СУБД честно сложит детальные строки, получит итоговый 0 и выведет строку, поскольку на временные таблицы пользователя автоматические условия HAVING платформы 1С не накладываются.Давайте посмотрим на практический пример реализации этого способа в коде запроса:
ВЫБРАТЬ
ХозрасчетныйОбороты.Субконто1 КАК Товар,
ХозрасчетныйОбороты.СуммаОборот КАК СуммаОборот
ПОМЕСТИТЬ ВТ_ДетальныеОбороты
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(&НачалоПериода, &КонецПериода, Запись, Счет = &СчетУчета, , , , ) КАК ХозрасчетныйОбороты
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_ДетальныеОбороты.Товар КАК Товар,
СУММА(ВТ_ДетальныеОбороты.СуммаОборот) КАК СуммаОборот
ИЗ
ВТ_ДетальныеОбороты КАК ВТ_ДетальныеОбороты
СГРУППИРОВАТЬ ПО
ВТ_ДетальныеОбороты.Товар
Этот подход гарантирует, что все товары, имевшие хоть какую-то активность в выбранном периоде, попадут в итоговый отчет с честным нулевым результатом, даже если их обороты полностью компенсировали друг друга.
Если по каким-то причинам вы не хотите использовать временные таблицы, можно обратиться напрямую к таблице движений регистра бухгалтерии — РегистрБухгалтерии.Хозрасчетный. Однако этот способ требует от разработчика повышенного внимания к деталям и понимания структуры хранения данных.
При работе с физической таблицей движений необходимо учитывать два важнейших нюанса:
ГДЕ Активность = ИСТИНА. Иначе в отчет попадет некорректная информация.Проанализируем пример запроса к физической таблице движений:
ВЫБРАТЬ
ХозрасчетныйДвижения.СубконтоДт1 КАК Товар,
СУММА(ВЫБОР
КОГДА ХозрасчетныйДвижения.СчетДт = &СчетУчета
ТОГДА ХозрасчетныйДвижения.Сумма
ИНАЧЕ -ХозрасчетныйДвижения.Сумма
КОНЕЦ) КАК СуммаОборот
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК ХозрасчетныйДвижения
ГДЕ
ХозрасчетныйДвижения.Период МЕЖДУ &НачалоПериода И &КонецПериода
И ХозрасчетныйДвижения.Активность = ИСТИНА
И (ХозрасчетныйДвижения.СчетДт = &СчетУчета ИЛИ ХозрасчетныйДвижения.СчетКт = &СчетУчета)
СГРУППИРОВАТЬ ПО
ХозрасчетныйДвижения.СубконтоДт1
Этот способ работает быстро на небольших объемах данных, но уступает первому способу в гибкости, так как вам приходится вручную описывать всю логику бухгалтерского учета, которую платформа в виртуальных таблицах берет на себя.
Часто бизнес-требования к отчету звучат так: «Мы хотим видеть в отчете абсолютно все товары из каталога (или определенной группы), и если по товару не было движений или обороты нулевые, напротив него должен стоять ноль». В этом случае лучшим решением будет использование механизма левого соединения.
Алгоритм реализации этого подхода:
Справочник.Номенклатура (при необходимости отбираем их во временную таблицу по группе или свойствам).ЛЕВОЕ СОЕДИНЕНИЕ по полю связи (Товар/Субконто).ЕСТЬNULL(). Если для товара не нашлось записей в оборотах (или они схлопнулись), СУБД вернет значение NULL, которое функция ЕСТЬNULL() превратит в красивый и понятный пользователю 0.Посмотрим на пример реализации левого соединения:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
ЕСТЬNULL(ХозрасчетныйОбороты.СуммаОборот, 0) КАК СуммаОборот
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Обороты(&НачалоПериода, &КонецПериода, , Счет = &СчетУчета, , , , ) КАК ХозрасчетныйОбороты
ПО Номенклатура.Ссылка = ХозрасчетныйОбороты.Субконто1
ГДЕ
Номенклатура.ЭтоГруппа = ЛОЖЬ
Этот метод незаменим при формировании инвентаризационных ведомостей, прайс-листов с остатками и других аналитических отчетов, где критически важно видеть весь ассортимент компании.
Если вы разрабатываете отчет на СКД, помните, что компоновщик макета СКД оптимизирует запросы на свое усмотрение. Если в схеме компоновки данных у полей периодов виртуальной таблицы настроена роль «Период», СКД может сама исключать строки с нулевыми итогами на этапе компоновки.
Для того чтобы избежать нежелательного поведения в СКД, рекомендуется:
Применяя данные подходы, вы сможете создавать точные и надежные отчеты, которые никогда не потеряют важные данные из-за специфики работы СУБД с нулевыми значениями.