Как исправить запрос в 1С, если при фильтрации оборотов пропадают остатки на диаграмме

Программист 1С v8.3 (Обычные формы) Управленческий учет
← На главную

При построении сложных аналитических отчетов в 1С, особенно тех, что визуализируются в виде диаграмм (графиков), программисты часто сталкиваются с проблемой «исчезновения» данных. Типичная ситуация: на графике должны отображаться столбики продаж и линия остатков. Как только мы накладываем фильтр, например, исключаем документы списания из оборотов, с графика пропадают не только эти обороты, но и линия остатков, а иногда и вся номенклатура. Разберем подробно, почему это происходит и как правильно спроектировать такой запрос.

Анализируем причину проблемы: логическая ловушка «пустого фильтра»

Рассмотрим структуру запроса, с которым возникла проблема. В нем последовательно формируются временные таблицы. Одной из ключевых является таблица НоменклатураОтбор. Проанализируем, как она заполняется в исходном варианте:


ВЫБРАТЬ
    ТаблицаОборотов.НоменклатураНоменклатурнаяГруппа КАК НоменклатурнаяГруппа
ПОМЕСТИТЬ НоменклатураОтбор
ИЗ
    ТаблицаОборотов КАК ТаблицаОборотов
СГРУППИРОВАТЬ ПО
    ТаблицаОборотов.НоменклатураНоменклатурнаяГруппа ;

В чем здесь кроется ошибка? Данная таблица строится исключительно на основании данных из ТаблицаОборотов. Если в ТаблицаОборотов из-за наложенного фильтра (например, ГДЕ НЕ Регистратор ССЫЛКА Документ.СписаниеТоваров) не попало ни одной записи по определенному товару, то этот товар не попадет и в таблицу НоменклатураОтбор.

Далее в запросе выполняется ПОЛНОЕ СОЕДИНЕНИЕ производственного календаря с таблицей НоменклатураОтбор по условию ИСТИНА. Это делается для того, чтобы создать «сетку» из всех возможных периодов для каждой номенклатуры. Но если НоменклатураОтбор пуста, то и результат этого соединения будет пустым. В итоге последующие левые соединения с таблицами остатков не находят «точек соприкосновения», и мы получаем NULL во всех полях. Линия остатков на графике прерывается или исчезает совсем, так как системе не к чему «привязать» эти данные по оси времени и номенклатуры.

Разберем правильный подход к формированию списка номенклатуры

Для того чтобы остатки (черная линия на графике) отображались независимо от наличия оборотов (цветные столбики), список номенклатуры для «сетки» запроса нужно брать из максимально широкого источника. Рассмотрим два варианта решения:

  1. Объединение источников: Сформируем НоменклатураОтбор путем объединения (ОБЪЕДИНИТЬ) номенклатуры из таблицы оборотов и таблицы остатков. Тогда, даже если продаж не было, но товар есть на складе, он попадет в выборку.
  2. Использование справочника: Если мы работаем в рамках конкретной группы товаров (параметр &Номенклатура), лучше всего выбрать список номенклатуры напрямую из справочника Номенклатура, наложив условие В ИЕРАРХИИ.

Посмотрим на пример реализации первого варианта:


ВЫБРАТЬ Номенклатура КАК НоменклатурнаяГруппа ПОМЕСТИТЬ НоменклатураОтбор ИЗ (
    ВЫБРАТЬ Номенклатура ИЗ ТаблицаОборотов
    ОБЪЕДИНИТЬ
    ВЫБРАТЬ Номенклатура ИЗ ТаблицаОстатков
) КАК ВложенныйЗапрос

Проблема фильтрации по Регистратору в виртуальных таблицах

В исходном запросе используется условие в блоке ГДЕ для виртуальной таблицы Обороты. Проанализируем ситуацию: использование Регистратор ССЫЛКА в виртуальных таблицах с периодичностью Авто — это ресурсоемкая операция.

Виртуальная таблица Обороты работает эффективно, когда она берет готовые итоги. Как только вы обращаетесь к полю Регистратор, системе приходится обращаться к физической таблице движений. Если ваша задача — исключить конкретные типы документов, стоит рассмотреть возможность обращения напрямую к физической таблице регистра накопления ПартииТоваровНаСкладах или ТоварыНаСкладах, особенно если вам важна высокая производительность.

Однако, если мы остаемся в рамках виртуальной таблицы, важно помнить: условие ГДЕ накладывается после того, как виртуальная таблица подготовила данные. Это еще одна причина, почему данные могут исчезнуть непредсказуемо. Выясним причину: если за весь месяц было только одно движение (списание), и вы его отсекли условием ГДЕ, то запись за этот месяц в таблицу оборотов вообще не попадет.

Как правильно рассчитать остатки на каждую дату (месяц)

В запросе автора используется метод накопления итога через неравенство периодов:


ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаОстатков КАК ТаблицаОстатков 
ПО ДатыКалендаря.Месяц >= ТаблицаОстатков.Период

Проанализируем этот подход. Это классический способ получения остатков «на каждый период», но он имеет существенный недостаток: квадратичную сложность. Если товаров много, а период отчета — несколько лет, запрос будет выполняться крайне медленно.

Рекомендация: Если есть возможность, используйте Систему Компоновки Данных (СКД). В СКД достаточно выбрать виртуальную таблицу ОстаткиИОбороты с периодичностью Месяц. СКД сама умеет дополнять периоды и рассчитывать остатки на начало и конец каждого месяца, даже если в этом месяце не было движений. Это избавит вас от необходимости использовать РегламентированныйПроизводственныйКалендарь и сложные соединения.

Работа с производственным календарем и сезонностью

Зачем в данном запросе используется РегистрСведений.РегламентированныйПроизводственныйКалендарь? Посмотрим на ситуацию: диаграмма требует непрерывной оси X (времени). Если в апреле не было ни одной операции, запрос без календаря просто пропустит этот месяц. На графике точка «Март» соединится с точкой «Май», что исказит восприятие реальности. Календарь служит «каркасом», на который мы навешиваем данные.

Также в запросе реализован расчет сезонности через конструкцию ВЫБОР КОГДА МЕСЯЦ(...). Это отличное решение для группировки данных по кварталам или сезонам прямо в запросе. Однако не забывайте, что при группировке по сезонам вы должны также группировать и числовые показатели (суммировать их).

Итоговые рекомендации по исправлению запроса

Для того чтобы ваша диаграмма отображалась корректно и не пропадала при фильтрации, выполните следующие шаги:

  1. Замените источник номенклатуры: Формируйте таблицу НоменклатураОтбор независимо от таблицы оборотов. Используйте для этого либо справочник, либо объединение всех таблиц-источников данных.
  2. Используйте ЕСТЬNULL: При выводе данных в финальную таблицу обязательно обрабатывайте все числовые ресурсы функцией ЕСТЬNULL(Поле, 0). Для диаграммы NULL — это отсутствие точки (пустота), а 0 — это точка на нулевой координате.
  3. Оптимизируйте периодичность: Если вам нужны данные по месяцам, указывайте в параметрах виртуальной таблицы периодичность МЕСЯЦ вместо Авто. Это позволит системе использовать предварительно рассчитанные итоги.
  4. Разделите логику: Получайте обороты (для столбиков) и остатки (для линии) в разных временных таблицах, а затем соединяйте их с «мастер-таблицей», которая содержит все периоды и всю номенклатуру.

Проанализировав эти моменты и применив их на практике, вы получите стабильный отчет, в котором списание товаров будет корректно уменьшать остаток (черную линию), но не будет влиять на отображение других данных и не приведет к исчезновению номенклатуры с графика.

← На главную