При разработке отчетов на системе компоновки данных (СКД) программисты часто сталкиваются с загадочным поведением: если в настройках отчета выбраны поля оборотов (приход или расход), номенклатура с нулевым остатком отображается корректно. Однако стоит убрать эти поля и оставить только конечный остаток, как строки с нулевыми значениями бесследно исчезают из результата. Давайте подробно разберем, почему это происходит и как спроектировать запрос так, чтобы отчет работал ожидаемо в любых режимах.
Первое, что нам необходимо понять — это механизм динамического формирования SQL-запросов в СКД. Система компоновки данных не просто выполняет тот текст запроса, который вы написали в схеме. Она анализирует выбранные пользователем поля, отборы и группировки, а затем «на лету» пересобирает запрос к базе данных, выбрасывая из него все, что считает лишним.
Когда мы используем виртуальную таблицу РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты, платформа 1С ведет себя следующим образом:
Проблема заключается в том, что в физических таблицах итогов 1С (особенно в таких конфигурациях, как УТ 11, ERP или КА) записи с нулевыми значениями часто просто не хранятся. Если ресурс закрылся в ноль, платформа может удалить соответствующую запись для экономии места и ускорения работы. В результате, обращаясь только к остаткам, мы не получаем записи о номенклатуре, по которой нет фактического остатка на складе.
Наиболее правильным и архитектурно верным способом решения данной задачи является использование справочника Номенклатура в качестве «мастер-таблицы». Это гарантирует, что в выборку попадут все нужные нам позиции, независимо от наличия движений в регистре.
Рассмотрим по шагам, как построить такой запрос:
ОстаткиИОбороты.NULL с помощью функции ЕСТЬNULL.Проанализируем пример кода запроса:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Номенклатура,
СправочникНоменклатура.Код КАК Код,
ЕСТЬNULL(ТоварыНаСкладахОстатки.ВНаличииКонечныйОстаток, 0) КАК КонечныйОстаток,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ) КАК ТоварыНаСкладахОстатки
ПО СправочникНоменклатура.Ссылка = ТоварыНаСкладахОстатки.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&КонецПериода, ) КАК ЦеныНоменклатурыСрезПоследних
ПО СправочникНоменклатура.Ссылка = ЦеныНоменклатурыСрезПоследних.Номенклатура
ГДЕ
НЕ СправочникНоменклатура.ЭтоГруппа
В этом случае, даже если в таблице остатков нет записи для конкретной позиции, Справочник.Номенклатура вернет строку, а функция ЕСТЬNULL превратит пустоту в аккуратный ноль.
Иногда даже при правильном запросе СКД может продолжать скрывать строки. Это связано с тем, как настроены Роли на закладке «Наборы данных». Рассмотрим, на что стоит обратить внимание:
КонечныйОстаток).Остаток).Важно помнить: если вы установили флаг «Обязательное» для поля номенклатуры в запросе, это заставляет СКД всегда включать это поле в итоговый запрос SQL, но это не отменяет логику работы виртуальной таблицы. Само по себе свойство «Обязательное» не вытащит данные из воздуха, если их нет в исходной выборке регистра.
Если ваша задача — вывести остатки по дням, включая те дни, когда движений не было вовсе, вам поможет механизм Дополнения периодов в СКД. Разберем, как его настроить:
ПериодДень) установите тип дополнения «День».&НачалоПериода и &КонецПериода).В этом режиме СКД самостоятельно сгенерирует недостающие строки для каждой даты внутри интервала. Если на начало дня остаток был 10, а движений не было три дня, система «протянет» этот остаток через все пустые даты.
В тексте вопроса упоминалось соединение с ценами. Если вы используете Внутреннее соединение (Inner Join) между остатками и ценами, то номенклатура исчезнет из отчета, если для нее не установлена цена, даже если товар есть на складе. Всегда используйте Левое соединение от основного списка товаров к регистру цен, чтобы отсутствие цены не приводило к исчезновению самой позиции из списка.
Также проанализируем ситуацию с NULL в ресурсах. В настройках компоновки на уровне отчета или группировки есть флаг «Игнорировать значения NULL». Если он установлен, а ваш запрос вернул NULL вместо 0 (потому что вы забыли ЕСТЬNULL), СКД просто скроет эту строку. Проверьте настройки оформления и убедитесь, что для пустых значений не задано скрытие.
Для того чтобы ваш отчет всегда корректно отображал номенклатуру, даже если ее остаток равен нулю:
Справочник.Номенклатура левой таблицей при соединении с регистрами.ЕСТЬNULL(Поле, 0) для всех числовых показателей.Соблюдение этих правил позволит вам создавать надежные отчеты, которые не «теряют» данные при изменении состава колонок пользователем.