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