Как в отчете соединить остатки оборудования из регистра накопления с его актуальным состоянием из регистра сведений

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

При разработке систем учета оборудования в среде 1С часто возникает задача объединения количественных данных (остатков на складах) и качественных характеристик, которые меняются во времени (состояние, статус, ответственное лицо). Рассмотрим ситуацию, когда у нас есть регистр накопления с данными об инвентарных номерах и товарах, а также периодический регистр сведений, где хранится история состояний этого оборудования. Наша цель — получить отчет, в котором для каждой единицы оборудования будет указано ее текущее местоположение и актуальное (последнее) состояние.

Анализ структуры данных

Прежде чем приступать к написанию запроса, проанализируем структуру наших регистров. Для корректного решения задачи нам понадобятся:

  1. Регистр накопления (Остатки): Здесь мы храним измерения ИнвНомер, Номенклатура, Склад и ресурс Количество. Из этого регистра мы будем получать список оборудования, которое в данный момент числится в учете.
  2. Регистр сведений (Состояние оборудования): Этот регистр должен быть периодическим. Это критически важно, так как именно периодичность позволяет использовать механизм среза последних данных. В качестве измерений должен выступать ИнвНомер, а в качестве ресурсов — Состояние.

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

Базовый подход: Использование Левого Соединения

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

Рассмотрим пример кода запроса:


ВЫБРАТЬ
    ОстаткиТоваров.ИнвНомер КАК ИнвНомер,
    ОстаткиТоваров.Номенклатура КАК Товар,
    ОстаткиТоваров.Склад КАК Склад,
    СостояниеСрезПоследних.Состояние КАК ТекущееСостояние
ИЗ
    РегистрНакопления.ОстаткиТоваров.Остатки(&Период, ) КАК ОстаткиТоваров
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостояниеОборудования.СрезПоследних(&Период, ) КАК СостояниеСрезПоследних
        ПО ОстаткиТоваров.ИнвНомер = СостояниеСрезПоследних.ИнвНомер

В данном примере мы обращаемся к виртуальным таблицам Остатки и СрезПоследних. Условие связи ПО ОстаткиТоваров.ИнвНомер = СостояниеСрезПоследних.ИнвНомер позволяет сопоставить конкретную железку с ее статусом.

Проблема производительности: Почему прямое соединение — это не всегда хорошо

Проанализируем ситуацию с точки зрения производительности СУБД. При прямом соединении двух виртуальных таблиц 1С генерирует сложный SQL-запрос, который может работать медленно на больших объемах данных (тысячи и десятки тысяч записей). Система сначала пытается выполнить вложенные подзапросы для каждой таблицы, а затем соединить их результаты.

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

Оптимизированное решение с использованием временных таблиц

Шаг 1: Сначала выберем все остатки во временную таблицу и проиндексируем ее по ключевому полю.


ВЫБРАТЬ
    ОстаткиТоваров.ИнвНомер КАК ИнвНомер,
    ОстаткиТоваров.Номенклатура КАК Номенклатура,
    ОстаткиТоваров.Склад КАК Склад
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
    РегистрНакопления.ОстаткиТоваров.Остатки(&Период, ) КАК ОстаткиТоваров
;
////////////////////////////////////////////////////////////////////////////////
ИНДЕКСИРОВАТЬ ПО
    ИнвНомер

Шаг 2: Теперь выберем данные из среза последних только для того оборудования, которое есть в нашей временной таблице. Это значительно сократит объем обрабатываемых данных.


ВЫБРАТЬ
    СостояниеОборудованияСрезПоследних.ИнвНомер КАК ИнвНомер,
    СостояниеОборудованияСрезПоследних.Состояние КАК Состояние
ПОМЕСТИТЬ ВТ_Состояния
ИЗ
    РегистрСведений.СостояниеОборудования.СрезПоследних(&Период, ИнвНомер В (ВЫБРАТЬ ИнвНомер ИЗ ВТ_Остатки)) КАК СостояниеОборудованияСрезПоследних
;
////////////////////////////////////////////////////////////////////////////////
ИНДЕКСИРОВАТЬ ПО
    ИнвНомер

Шаг 3: Соединим две подготовленные и проиндексированные временные таблицы в итоговом пакете запроса.


ВЫБРАТЬ
    ВТ_Остатки.ИнвНомер,
    ВТ_Остатки.Номенклатура,
    ВТ_Остатки.Склад,
    ЕСТЬNULL(ВТ_Состояния.Состояние, "Состояние не задано") КАК Состояние
ИЗ
    ВТ_Остатки КАК ВТ_Остатки
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Состояния КАК ВТ_Состояния
        ПО ВТ_Остатки.ИнвНомер = ВТ_Состояния.ИнвНомер

Использование функции ЕСТЬNULL позволяет нам вывести понятный текст, если информация в регистре сведений отсутствует.

Тонкости настройки периодичности

При работе с состоянием оборудования важно правильно выбрать периодичность регистра сведений. Рассмотрим два варианта:

Использование Системы Компоновки Данных (СКД)

Если вы новичок и создание сложных запросов с временными таблицами кажется вам трудоемким, воспользуйтесь механизмом Связи наборов данных в СКД. Вы можете создать два простых набора данных-запроса:

  1. Первый набор выбирает остатки из регистра накопления.
  2. Второй набор выбирает данные из среза последних регистра сведений.

На закладке "Связи наборов данных" укажите связь по полю ИнвНомер. В этом случае СКД сама сформирует эффективные запросы к базе данных, передавая инвентарный номер из первого набора в параметры виртуальной таблицы второго набора. Это "ленивый", но весьма эффективный способ решения задачи для типовых отчетов.

Таким образом, мы выяснили, что для получения корректного отчета необходимо не только правильно написать запрос с использованием ЛЕВОЕ СОЕДИНЕНИЕ и СрезПоследних, но и уделить внимание архитектуре регистров: сделать регистр сведений периодическим и вынести состояние в ресурсы.

← На главную