Как получить значение реквизита регистра в запросе к виртуальной таблице остатков?

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

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

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

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

Рассмотрим пример из практики. Допустим, у нас есть регистр ДефицитПродукции. В нем есть измерения Номенклатура и Документ, и реквизит ЗаказПоставщику. Если мы попытаемся написать запрос напрямую к остаткам, мы потерпим неудачу:


ВЫБРАТЬ
    ДефицитПродукцииОстатки.Номенклатура КАК Номенклатура,
    ДефицитПродукцииОстатки.ЗаказПоставщику, // ОШИБКА: Поле не найдено
    ДефицитПродукцииОстатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ДефицитПродукции.Остатки(&ДатаОстатков) КАК ДефицитПродукцииОстатки

Решение 1: Перенос реквизита в измерения

Это самый правильный метод с точки зрения архитектуры, если вам требуется получать остатки именно в разрезе этого значения. Если бизнес-логика подразумевает, что остаток по Номенклатуре должен быть детализирован до ЗаказаПоставщику, то это поле обязано быть Измерением.

Преимущества:

Минусы:

Решение 2: Запрос к физической таблице регистра

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

Проанализируем пример такого запроса:


ВЫБРАТЬ
    ДефицитПродукции.Номенклатура КАК Номенклатура,
    ДефицитПродукции.ЗаказПоставщику КАК ЗаказПоставщику,
    СУММА(ВЫБОР
            КОГДА ДефицитПродукции.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
                ТОГДА ДефицитПродукции.Количество
            ИНАЧЕ -ДефицитПродукции.Количество
        КОНЕЦ) КАК Остаток
ИЗ
    РегистрНакопления.ДефицитПродукции КАК ДефицитПродукции
ГДЕ
    ДефицитПродукции.Период <= &МоментВремени
СГРУППИРОВАТЬ ПО
    ДефицитПродукции.Номенклатура,
    ДефицитПродукции.ЗаказПоставщику
ИМЕЮЩИЕ
    СУММА(ВЫБОР
            КОГДА ДефицитПродукции.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
                ТОГДА ДефицитПродукции.Количество
            ИНАЧЕ -ДефицитПродукции.Количество
        КОНЕЦ) > 0

Важно: Этот метод будет работать крайне медленно на больших объемах данных, так как 1С придется пересчитывать все записи регистра с начала времен. Также необходимо учитывать Разделитель итогов в версии 8.3 — данные в физической таблице могут быть временно неактуальны до момента фиксации транзакции.

Решение 3: Соединение остатков с физической таблицей (Метод последнего движения)

Если вам нужно получить остаток и какой-то реквизит из последнего документа, который сделал движение, следует использовать комбинированный подход. Мы сначала получаем актуальные остатки, а затем соединяем их с физической таблицей для получения дополнительной информации.

Разберем по шагам:

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

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

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

// 3. Соединяем все вместе
ВЫБРАТЬ
    Остатки.Номенклатура,
    Остатки.Количество,
    Рег.ЗаказПоставщику // Теперь реквизит доступен!
ИЗ
    ВТ_Остатки КАК Остатки
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПоследниеЗаписи КАК Последние
    ПО Остатки.Номенклатура = Последние.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ДефицитПродукции КАК Рег
    ПО Последние.МаксМомент = Рег.МоментВремени 
    И Остатки.Номенклатура = Рег.Номенклатура

Решение 4: Виртуальная таблица ОстаткиИОбороты

Рассмотрим еще один интересный способ. Виртуальная таблица ОстаткиИОбороты при установке периодичности в значение Запись позволяет получить доступ к полям Регистратор и НомерСтроки.

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

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

Рекомендации по оптимизации

Проанализировав все способы, подведем итог. Выбор метода зависит от ваших целей:

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

← На главную