Как в запросе выбрать реквизиты с регистров накопления

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

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

В этой статье мы подробно разберем, почему реквизиты недоступны в виртуальных таблицах, какими способами их можно получить и как при этом не допустить критических ошибок в производительности и логике данных.

Почему реквизитов нет в таблице остатков?

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

Способ 1. Левое соединение с физической таблицей регистра

Разберем самый прямолинейный способ, который часто применяют на практике: соединение виртуальной таблицы остатков с основной (физической) таблицей регистра. Рассмотрим ситуацию на примере регистра КоличествоКнигУПользователя.

Для того чтобы получить реквизит, нам необходимо «приклеить» данные из основной таблицы к данным об остатках по ключевым полям (измерениям). Посмотрим на пример запроса:


ВЫБРАТЬ
    Остатки.Пользователь КАК Пользователь,
    Остатки.Книги КАК Книги,
    Остатки.КоличествоКнигОстаток КАК КоличествоКнигОстаток,
    Движения.ПлановаяДатаВозврата КАК ПлановаяДатаВозврата
ИЗ
    РегистрНакопления.КоличествоКнигУПользователя.Остатки(&Период, ) КАК Остатки
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.КоличествоКнигУПользователя КАК Движения
        ПО Остатки.Пользователь = Движения.Пользователь
            И Остатки.Книги = Движения.Книги
ГДЕ
    Движения.Активность = ИСТИНА

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

Способ 2. Группировка данных для исключения дублей

Чтобы избежать «размножения» строк при соединении, выясним причину дублей и устраним ее с помощью агрегатных функций. Если нам нужно получить, например, самую позднюю дату возврата, мы должны использовать МАКСИМУМ. Проанализируем правильный алгоритм:

  1. Выбираем данные из таблицы остатков.
  2. Соединяем с подзапросом или сгруппированной физической таблицей.
  3. Применяем агрегатную функцию к реквизиту.

ВЫБРАТЬ
    Остатки.Пользователь КАК Пользователь,
    Остатки.Книги КАК Книги,
    Остатки.КоличествоКнигОстаток КАК Остаток,
    МАКСИМУМ(Движения.ПлановаяДатаВозврата) КАК ПоследняяДатаВозврата
ИЗ
    РегистрНакопления.КоличествоКнигУПользователя.Остатки КАК Остатки
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.КоличествоКнигУПользователя КАК Движения
        ПО Остатки.Пользователь = Движения.Пользователь
            И Остатки.Книги = Движения.Книги
СГРУППИРОВАТЬ ПО
    Остатки.Пользователь,
    Остатки.Книги,
    Остатки.КоличествоКнигОстаток

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

Способ 3. Оптимизация через временные таблицы

Если в регистре накопления миллионы записей, прямое соединение «повесит» систему. Рассмотрим профессиональный подход с использованием временных таблиц:

  1. Сначала поместим нужные нам остатки во временную таблицу ВТ_Остатки. Это значительно сузит круг поиска.
  2. Проиндексируем временную таблицу по измерениям.
  3. Соединим физическую таблицу регистра только с теми записями, которые попали в ВТ_Остатки.

// Шаг 1: Получаем остатки во временную таблицу
ВЫБРАТЬ
    Остатки.Пользователь,
    Остатки.Книги,
    Остатки.КоличествоКнигОстаток
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
    РегистрНакопления.КоличествоКнигУПользователя.Остатки КАК Остатки
;

// Шаг 2: Получаем реквизиты с фильтром по остаткам
ВЫБРАТЬ
    ВТ_Остатки.Пользователь,
    ВТ_Остатки.Книги,
    ВТ_Остатки.КоличествоКнигОстаток,
    МАКСИМУМ(Регистр.ПлановаяДатаВозврата) КАК ПлановаяДата
ИЗ
    ВТ_Остатки КАК ВТ_Остатки
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.КоличествоКнигУПользователя КАК Регистр
        ПО ВТ_Остатки.Пользователь = Регистр.Пользователь
            И ВТ_Остатки.Книги = Регистр.Книги
СГРУППИРОВАТЬ ПО
    ВТ_Остатки.Пользователь,
    ВТ_Остатки.Книги,
    ВТ_Остатки.КоличествоКнигОстаток

Способ 4. Использование виртуальной таблицы «Остатки и обороты»

Существует еще один метод — использование таблицы ОстаткиИОбороты. Если в параметрах таблицы указать периодичность Регистратор, нам станут доступны поля регистратора. Через точку от регистратора можно получить его реквизиты, но это крайне неэффективно с точки зрения производительности СУБД.

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

Архитектурно правильное решение

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

Рассмотрим два варианта качественного изменения архитектуры:

  1. Регистр сведений: Храните плановую дату возврата в периодическом регистре сведений. В запросе вы просто соедините две виртуальные таблицы: Остатки регистра накопления и СрезПоследних регистра сведений. Это самый быстрый и надежный способ в 1С.
  2. Измерение: Сделайте ПлановаяДатаВозврата измерением регистра накопления. Тогда вы сможете видеть остатки в разрезе дат. Но помните: если дат будет слишком много, это «раздует» таблицу итогов и замедлит проведение документов.

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

← На главную