Разработчики 1С часто сталкиваются с ситуацией, когда при построении отчета или получении данных в коде необходимо вытащить не только измерения и ресурсы, но и реквизиты регистра накопления. Однако, открыв конструктор запроса и выбрав виртуальную таблицу Остатки, мы обнаруживаем, что нужных нам полей в списке просто нет. В этой статье мы подробно разберем, почему так происходит и какими способами можно обойти это платформенное ограничение.
Для начала проанализируем архитектуру регистров накопления. Виртуальная таблица Остатки формируется платформой динамически на основании итогов. Она выполняет агрегацию данных: суммирует ресурсы в разрезе измерений. Реквизит же — это справочная информация, привязанная к конкретной записи (движению) в физической таблице. Поскольку остаток на определенный момент времени — это результат сложения множества приходов и расходов, платформа «не знает», значение какого именно реквизита из десятков записей вам нужно показать. Именно поэтому в виртуальной таблице Остатки присутствуют только измерения и ресурсы.
Рассмотрим пример из практики. Допустим, у нас есть регистр ДефицитПродукции. В нем есть измерения Номенклатура и Документ, и реквизит ЗаказПоставщику. Если мы попытаемся написать запрос напрямую к остаткам, мы потерпим неудачу:
ВЫБРАТЬ
ДефицитПродукцииОстатки.Номенклатура КАК Номенклатура,
ДефицитПродукцииОстатки.ЗаказПоставщику, // ОШИБКА: Поле не найдено
ДефицитПродукцииОстатки.КоличествоОстаток
ИЗ
РегистрНакопления.ДефицитПродукции.Остатки(&ДатаОстатков) КАК ДефицитПродукцииОстатки
Это самый правильный метод с точки зрения архитектуры, если вам требуется получать остатки именно в разрезе этого значения. Если бизнес-логика подразумевает, что остаток по Номенклатуре должен быть детализирован до ЗаказаПоставщику, то это поле обязано быть Измерением.
Преимущества:
Минусы:
Если менять структуру регистра нельзя, мы можем обратиться напрямую к физической таблице. В этом случае мы сами эмулируем расчет остатков, группируя записи и суммируя их с учетом вида движения (Приход/Расход).
Проанализируем пример такого запроса:
ВЫБРАТЬ
ДефицитПродукции.Номенклатура КАК Номенклатура,
ДефицитПродукции.ЗаказПоставщику КАК ЗаказПоставщику,
СУММА(ВЫБОР
КОГДА ДефицитПродукции.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ДефицитПродукции.Количество
ИНАЧЕ -ДефицитПродукции.Количество
КОНЕЦ) КАК Остаток
ИЗ
РегистрНакопления.ДефицитПродукции КАК ДефицитПродукции
ГДЕ
ДефицитПродукции.Период <= &МоментВремени
СГРУППИРОВАТЬ ПО
ДефицитПродукции.Номенклатура,
ДефицитПродукции.ЗаказПоставщику
ИМЕЮЩИЕ
СУММА(ВЫБОР
КОГДА ДефицитПродукции.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ДефицитПродукции.Количество
ИНАЧЕ -ДефицитПродукции.Количество
КОНЕЦ) > 0
Важно: Этот метод будет работать крайне медленно на больших объемах данных, так как 1С придется пересчитывать все записи регистра с начала времен. Также необходимо учитывать Разделитель итогов в версии 8.3 — данные в физической таблице могут быть временно неактуальны до момента фиксации транзакции.
Если вам нужно получить остаток и какой-то реквизит из последнего документа, который сделал движение, следует использовать комбинированный подход. Мы сначала получаем актуальные остатки, а затем соединяем их с физической таблицей для получения дополнительной информации.
Разберем по шагам:
Максимальный Период или Максимальный МоментВремени в физической таблице.
// 1. Получаем остатки
ВЫБРАТЬ
Остатки.Номенклатура КАК Номенклатура,
Остатки.КоличествоОстаток КАК Количество
ПОМЕСТИТЬ ВТ_Остатки
ИЗ
РегистрНакопления.ДефицитПродукции.Остатки(&Дата) КАК Остатки;
// 2. Находим последние записи для этих остатков
ВЫБРАТЬ
Т.Номенклатура,
МАКСИМУМ(Физика.МоментВремени) КАК МаксМомент
ПОМЕСТИТЬ ВТ_ПоследниеЗаписи
ИЗ
ВТ_Остатки КАК Т
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ДефицитПродукции КАК Физика
ПО Т.Номенклатура = Физика.Номенклатура
СГРУППИРОВАТЬ ПО
Т.Номенклатура;
// 3. Соединяем все вместе
ВЫБРАТЬ
Остатки.Номенклатура,
Остатки.Количество,
Рег.ЗаказПоставщику // Теперь реквизит доступен!
ИЗ
ВТ_Остатки КАК Остатки
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПоследниеЗаписи КАК Последние
ПО Остатки.Номенклатура = Последние.Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ДефицитПродукции КАК Рег
ПО Последние.МаксМомент = Рег.МоментВремени
И Остатки.Номенклатура = Рег.Номенклатура
Рассмотрим еще один интересный способ. Виртуальная таблица ОстаткиИОбороты при установке периодичности в значение Запись позволяет получить доступ к полям Регистратор и НомерСтроки.
Выясним, как это использовать: через регистратор и номер строки можно выполнить ЛЕВОЕ СОЕДИНЕНИЕ с основной физической таблицей регистра. В этом случае вы получите остаток на момент каждой конкретной записи вместе со всеми ее реквизитами.
Внимание: Этот метод крайне ресурсозатратный. Используйте его только для небольших выборок или в отчетах, где важна история изменения реквизита вместе с остатком.
Проанализировав все способы, подведем итог. Выбор метода зависит от ваших целей:
Номенклатура или связанного Регистра сведений.Таким образом, хотя «прямого» способа получить реквизит в виртуальной таблице остатков не существует, комбинация временных таблиц и соединений позволяет решить задачу любой сложности, сохраняя при этом приемлемую производительность системы.