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