При разработке отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с неприятным эффектом: при добавлении в запрос левого соединения (ЛЕВОЕ СОЕДИНЕНИЕ) к виртуальной таблице остатков и оборотов, значения в колонках начального и конечного остатка начинают суммироваться. Это происходит в тех случаях, когда отчет выводится без детальных записей по регистратору. Рассмотрим подробнее, почему это происходит, и проанализируем эффективные способы решения этой задачи.
Для начала разберем, как 1С работает с ресурсами типа "Остаток". В отличие от простых оборотов, которые можно просто складывать, остатки — это значения на конкретный момент времени. Чтобы СКД правильно вычисляла итоги по остаткам, ей необходимо четко понимать структуру запроса и роли полей.
Когда мы получаем реквизиты "через точку" от регистратора (например, Регистратор.Дата), СКД самостоятельно оптимизирует запрос. Она понимает, что это обращение к реквизиту уже существующего объекта, и не нарушает логику расчета итогов виртуальной таблицы. Однако, как только мы пишем явное ЛЕВОЕ СОЕДИНЕНИЕ в тексте запроса, мы берем управление структурой на себя.
Проанализируем ситуацию: если в результате соединения одной записи из таблицы остатков соответствуют несколько записей из присоединяемой таблицы, происходит "размножение" строк. СКД видит плоскую таблицу и, если роли полей настроены неверно или не настроены вовсе, начинает применять агрегатную функцию СУММА ко всем числовым полям. В итоге начальный остаток, который должен быть неизменным для периода, складывается столько раз, сколько строк получилось в результате соединения.
Одним из самых быстрых и эффективных способов решения в рамках одного запроса является использование конструкций необязательных таблиц. Посмотрим на пример кода, который позволяет обойти проблему суммирования:
ВЫБРАТЬ
ОстаткиНоменклатурыОстаткиИОбороты.Регистратор КАК Регистратор,
ОстаткиНоменклатурыОстаткиИОбороты.ПериодСекунда КАК ПериодСекунда,
ОстаткиНоменклатурыОстаткиИОбороты.КоличествоНачальныйОстаток КАК КоличествоНачальныйОстаток,
ОстаткиНоменклатурыОстаткиИОбороты.КоличествоПриход КАК КоличествоПриход,
ОстаткиНоменклатурыОстаткиИОбороты.КоличествоРасход КАК КоличествоРасход,
ОстаткиНоменклатурыОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток,
РасходнаяНакладная.Дата КАК Дата,
ОстаткиНоменклатурыОстаткиИОбороты.Номенклатура КАК Номенклатура
ИЗ
РегистрНакопления.ОстаткиНоменклатуры.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Авто, , ) КАК ОстаткиНоменклатурыОстаткиИОбороты
{ЛЕВОЕ СОЕДИНЕНИЕ Документ.РасходнаяНакладная КАК РасходнаяНакладная
ПО ОстаткиНоменклатурыОстаткиИОбороты.Регистратор = РасходнаяНакладная.Ссылка}
Обратите внимание на использование фигурных скобок {} вокруг оператора соединения. Это указывает СКД, что данную таблицу нужно подключать только в том случае, если поля из неё (в нашем примере это Дата) выбраны пользователем в настройках отчета. Если поле не выбрано, СКД полностью исключит соединение из итогового SQL-запроса, и расчет остатков пройдет в штатном режиме.
Если соединение необходимо всегда, выясним, как настроить роли полей на закладке "Наборы данных". Для корректного расчета остатков необходимо выполнить следующие шаги:
КоличествоНачальныйОстаток и КоличествоКонечныйОстаток откройте колонку "Роль".НачальныйОстаток, для конечного — КонечныйОстаток.ПериодСекунда). Это критически важно: СКД должна знать, по какой временной шкале "раскладывать" эти значения.Когда эти настройки заданы, СКД перестает использовать простую сумму и задействует внутренний алгоритм вычисления остатков, который учитывает измерения и временные метки, даже при наличии соединений.
Рассмотрим более архитектурно верный подход. Если логика отчета позволяет, лучше разделить запрос на два независимых набора данных:
ОстаткиИОбороты со всеми необходимыми измерениями и ресурсами.После этого перейдем на закладку "Связи наборов данных" и свяжем их по ключевым полям (например, по Регистратору или Номенклатуре). В этом случае СКД сначала получит корректные итоги по первому набору, а затем "подтянет" к ним данные из второго. Это полностью исключает риск дублирования остатков из-за особенностей SQL-соединений в одном запросе.
Иногда возникают ситуации, когда программист вносит верные правки в схему компоновки, но отчет продолжает выводить неверные данные. Проанализируем причину: платформа 1С активно кэширует структуру запросов СКД. Если вы столкнулись с тем, что настройки ролей не помогают:
Подводя итог, можно сказать, что проблема суммирования остатков — это не ошибка платформы, а следствие специфики работы с виртуальными таблицами. Использование необязательных соединений и корректная настройка ролей периодов являются наиболее предпочтительными методами решения данной задачи.