При разработке отчетов или написании запросов в платформе «1С:Предприятие» программисты часто сталкиваются с сообщением об ошибке: «Поле не найдено "Регистратор"». Эта ситуация возникает при попытке обратиться к стандартному реквизиту Регистратор в виртуальной таблице оборотов или остатков и оборотов регистра накопления. Начинающие разработчики часто не понимают, почему в физической таблице движений это поле присутствует, а при обращении к виртуальной таблице платформа выдает ошибку.
В этой статье мы подробно разберем природу возникновения данной ошибки, проанализируем внутреннее устройство СУБД при работе с регистрами накопления и рассмотрим наиболее эффективные способы решения этой проблемы с точки зрения производительности системы.
Для того чтобы понять, почему возникает ошибка, давайте заглянем «под капот» платформы 1С и СУБД. В системе «1С:Предприятие» регистры накопления хранят информацию в нескольких физических таблицах базы данных:
Регистратор присутствует всегда, так как каждая запись жестко привязана к конкретному документу, сделавшему движение.Номенклатура, Склад) за определенные периоды (обычно месяц). В физических таблицах итогов нет поля «Регистратор», так как данные там уже сгруппированы и очищены от информации о конкретных документах.Виртуальные таблицы (такие как .Обороты или .ОстаткиИОбороты) формируются платформой динамически в момент выполнения запроса. Если мы обращаемся к виртуальной таблице оборотов без указания специального параметра периодичности, платформа в целях оптимизации транслирует наш запрос к физической таблице итогов. Поскольку в таблице итогов регистратора нет, СУБД возвращает ошибку: Поле не найдено "ОбеспечениеПроизводственныхПроцессовОбороты.Регистратор".
Давайте рассмотрим два основных способа решения этой проблемы.
Если нам критически важно использовать именно виртуальную таблицу Обороты, мы должны явно указать платформе, что нам требуется детализация до конкретного документа. Для этого используется параметр Периодичность виртуальной таблицы.
Рассмотрим структуру параметров виртуальной таблицы оборотов:
РегистрНакопления.ИмяРегистра.Обороты(НачалоПериода, КонецПериода, Периодичность, Условие)
Третьим параметром мы можем передать предопределенное значение Регистратор. В этом случае платформа поймет, что обращаться нужно не к таблице готовых итогов, а к детальной таблице движений, группируя записи по регистратору. Давайте посмотрим на пример правильного построения такого запроса:
ВЫБРАТЬ
ОбеспечениеПроизводственныхПроцессовОбороты.Регистратор КАК Регистратор,
ОбеспечениеПроизводственныхПроцессовОбороты.Номенклатура КАК Номенклатура
ИЗ
РегистрНакопления.ОбеспечениеПроизводственныхПроцессов.Обороты(, , Регистратор, ) КАК ОбеспечениеПроизводственныхПроцессовОбороты
ГДЕ
ОбеспечениеПроизводственныхПроцессовОбороты.Регистратор Ссылка Документ.ЗаказНаПроизводство2_2
В данном случае запрос отработает без ошибок. Платформа успешно сопоставит поле Регистратор, так как мы явно переопределили периодичность построения виртуальной таблицы.
Хотя первый способ решает проблему синтаксической ошибки, с точки зрения производительности СУБД он часто является неоптимальным. Когда мы накладываем условие на регистратор через секцию ГДЕ в виртуальной таблице, СУБД сначала выбирает все движения по регистру за указанный период, группирует их, создает временную структуру и только потом фильтрует по нашему регистратору.
Если перед нами стоит задача получить данные по конкретному регистратору или по документам определенного типа, гораздо эффективнее обратиться напрямую к основной физической таблице движений регистра.
Давайте проанализируем этот подход на примере кода:
ВЫБРАТЬ
ОбеспечениеПроизводственныхПроцессов.Регистратор КАК Регистратор,
ОбеспечениеПроизводственныхПроцессов.Номенклатура КАК Номенклатура
ИЗ
РегистрНакопления.ОбеспечениеПроизводственныхПроцессов КАК ОбеспечениеПроизводственныхПроцессов
ГДЕ
ОбеспечениеПроизводственныхПроцессов.Регистратор Ссылка Документ.ЗаказНаПроизводство2_2
Разберем преимущества обращения к физической таблице движений:
Регистратор для всех физических таблиц движений регистров накопления. СУБД мгновенно найдет нужные записи в базе данных по индексу, избегая сканирования всей таблицы.Особенно опасным является использование отборов по регистратору в виртуальной таблице ОстаткиИОбороты. Проанализируем следующую ситуацию: разработчик указывает периодичность Регистратор и накладывает условие ГДЕ Таблица.Регистратор = &НужныйДокумент.
В результате выполнения такого запроса система вернет абсолютно неверные начальные и конечные остатки. Это логическая особенность работы платформы. Платформа рассчитывает остатки только на основании тех движений, которые попали в итоговую выборку после наложения условий. Исключив из выборки все остальные документы за всю историю ведения учета, система посчитает остатки так, будто в базе существовал только один этот документ.
Важное правило: Если вам необходимо получить остатки на момент проведения конкретного документа, никогда не используйте таблицу ОстаткиИОбороты с фильтрацией по регистратору через ГДЕ. Вместо этого используйте виртуальную таблицу Остатки, передавая в качестве параметра «Период» Новый Граница(ВашДокумент.МоментВремени(), ГраницаСмеси.Включая).
Подведем итоги нашего разбора. При возникновении ошибки отсутствия поля «Регистратор» придерживайтесь следующих правил проектирования запросов:
РегистрНакопления.ИмяРегистра). Это наиболее быстрый и надежный способ..Обороты, обязательно передавая в третий параметр конструктора таблицы значение Периодичность.Регистратор (или просто Регистратор в конструкторе запроса).