Работа с регистрами накопления — одна из базовых задач разработчика на платформе 1С:Предприятие. Часто возникает необходимость не просто получить суммы оборотов или остатков, но и определить, каким именно документом (регистратором) были сделаны соответствующие записи. В данной статье подробно разберем, как построить запрос для получения регистратора из виртуальной таблицы оборотов, какие существуют нюансы и альтернативные подходы.
Теоретические основы: Регистратор и виртуальные таблицы
В 1С каждый документ, проводящийся в регистр накопления, выступает в роли регистратора. При проведении документ создает набор записей в регистре, которые связаны с ним через системное измерение Регистратор (тип: ДокументСсылка) и системный реквизит НомерСтроки (для различения строк табличной части).
Платформа предоставляет доступ к данным регистров через виртуальные таблицы:
- Остатки (Балансы) — состояние на момент времени.
- Обороты (Turnovers) — движение за период (Приход, Расход, Оборот).
- Движения (Records) — «сырые» записи регистра без агрегации.
Важно: Виртуальная таблица
Оборотыпредназначена для агрегированных данных (сумм по измерениям за период). ПолеРегистраторв ней доступно, но его смысл при группировке требует понимания логики формирования записей.
Синтаксис запроса к виртуальной таблице Обороты
Для обращения к виртуальной таблице оборотов используется следующий синтаксис в языке запросов:
РЕГИСТРНАКОПЛЕНИЯ.<ИмяРегистра>.ОБОРОТЫ(
<Периодичность>,
<ГраницыПериода>,
<УсловиеОтбораПоИзмерениям>,
<СписокИзмеренийДляГруппировки>
) Параметры:
- Периодичность (Секунда, Минута, Час, День, Неделя, Месяц, Квартал, Полгода, Год, ГраницаПериода) — определяет гранулярность срезов времени.
- ГраницыПериода — начало и конец периода (например,
&НачалоПериода, &КонецПериода). - УсловиеОтбораПоИзмерениям — строка с условием WHERE для измерений (например,
Номенклатура = &Номенклатура). - СписокИзмеренийДляГруппировки, перечень полей (измерений, ресурсов, а также Регистратор, Период, НомерСтроки), по которым будет происходить группировка.
Основной сценарий: Получение регистратора для конкретной номенклатуры за период
Самая частая задача: «Найти документ, который списал/пришел определенный товар на складе за период».
Пример 1: Базовый запрос с группировкой по Регистратору
ВЫБРАТЬ
ТоварыНаСкладахОбороты.Регистратор,
ТоварыНаСкладахОбороты.Период,
ТоварыНаСкладахОбороты.Номенклатура,
ТоварыНаСкладахОбороты.Склад,
СУММА(ТоварыНаСкладахОбороты;КоличествоПриход) КАК КоличествоПриход,
СУММА(ТоварыНаСкладахОбороты.КоличествоРасход) КАК КоличествоРасход
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОБОРОТЫ(
,
,
Номенклатура = &Номенклатура И Склад = &Склад,
Регистратор, Период, Номенклатура, Склад
) КАК ТоварыНаСкладахОбороты
СГРУППИРОВАТЬ ПО
ТоварыНаСкладахОбороты.Регистратор,
ТоварыНаСкладахОбороты.Период,
ТоварыНаСкладахОбороты.Номенклатура,
ТоварыНаСкладахОбороты.Склад
УПОРЯДОЧИТЬ ПО
ТоварыНаСкладахОбороты.Период УБЫВ Разбор ключевых моментов:
- Параметр 4 (СписокИзмеренийДляГруппировки): Мы явно указали
Регистратор, Период. Это заставляет платформу не агрегировать все движения в одну строку за период, а разбить их по каждому регистратору и дате документа. - Поле Период: В виртуальной таблице Обороты поле
Периодпредставляет собой начало интервала периодичности (или дату регистратора, если периодичность = Секунда/ГраницаПериода). Для точной привязки к документу лучше использовать периодичность Секунда или ГраницаПериода. - Агрегатные функции: Поскольку мы группируем по Регистратору, ресурсы (КоличествоПриход, КоличествоРасход) нужно оборачивать в
СУММА(хотя в рамках одного регистратора и измерений строка обычно одна).
Пример 2: Получение «последнего» регистратора (Топ-1)
Если нужно узнать, какой документ последним двигал товар (например, для определения последней цены закупки):
ВЫБРАТЬ ПЕРВЫЕ 1
ТоварыНаСкладахОбороты.Регистратор,
ТоварыНаСкладахОбороты.Период,
ТоварыНаСкладахОбороты.КоличествоПриход,
ТоварыНаСкладахОбороты.СтоимостьПриход
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОБОРОТЫ(
ГраницаПериода,
&НачалоПериода, &КонецПериода,
Номенклатура = &Номенклатура,
Регистратор, Период
) КАК ТоварыНаСкладахОбороты
УПОРЯДОЧИТЬ ПО
ТоварыНаСкладахОбороты.Период УБЫВ Здесь использована периодичность ГраницаПериода — это самый эффективный способ получить строки, привязанные к конкретным моментам времени (датам документов), без лишних срезов по дням/месяцам.
Альтернативный (и часто более правильный) подход: Виртуальная таблица Движения
Если задача, получить подробные строки документа (все номенклатуру из конкретного документа, цены, характеристики, серии), использование таблицы Обороты с группировкой по Регистратору может быть избыточным и медленным (платформа все равно агрегирует данные перед выдачей).
Для этих целей идеально подходит виртуальная таблица Движения (Records):
ВЫБРАТЬ
ТоварыНаСкладахДвижения.Регистратор,
ТоварыНаСкладахДвижения.НомерСтроки,
ТоварыНаСкладахДвижения.Номенклатура,
ТоварыНаСкладахДвижения.Склад,
ТоварыНаСкладахДвижения.Количество,
ТоварыНаСкладахДвижения.Стоимость,
ТоварыНаСкладахДвижения.ВидДвижения
ИЗ
РегистрНакопления.ТоварыНаСкладах.ДВИЖЕНИЯ(
,
Регистратор = &Регистратор
) КАК ТоварыНаСкладахДвижения
УПОРЯДОЧИТЬ ПО
ТоварыНаСкладахДвижения.НомерСтроки Сравнение подходов
| Характеристика | Обороты (с группировкой по Регистратору) | Движения (Records) |
|---|---|---|
| Цель | Анализ итогов по документам за период (сколько пришло/ушло в каждом доке) | Получение полного состава строк конкретного документа(ов) |
| Производительность | Требует агрегации (может быть медленно на больших регистрах) | Чтение «сырых» записей по индексу (очень быстро) |
| Доступные поля | Только измерения, ресурсы, Регистратор, Период, НомерСтроки | Все реквизиты регистра (в т.ч. Характеристика, Серия, Цена, Партия и т.д.) |
| Фильтр по документу | Через условие отбора по измерениям + группировка | Прямой отбор Регистратор = &Ссылка (мгновенно) |
Типичные ошибки и нюансы
Ошибка 1: Забыли добавить Регистратор в 4-й параметр
Если в списке группировки (4-й параметр) не указать Регистратор, поле Регистратор в выборке будет недоступно (NULL) или запрос вернет ошибку, так как платформа не знает, что нужно сохранять это измерение при агрегации.
Ошибка 2: Использование периодичности «День»/«Месяц» для поиска документа
При периодичности «День» поле Период вернет 00:00:00 текущего дня. Если за день было несколько документов, они сольются в одну строку, и Регистратор станет неопределенным (или вернет первый попавшийся). Всегда используйте «Секунда» или «ГраницаПериода» для привязки к конкретному документу.
Ошибка 3: Попытка получить реквизиты регистратора (Номер, Дата, Контрагент) прямо из Оборотов
В виртуальной таблице Обороты доступен только сам объект-ссылка Регистратор. Чтобы получить его реквизиты, нужно сделать JOIN (СОЕДИНЕНИЕ) с таблицей документов или использовать точечную навигацию в СКД/Объекте запроса:
ВЫБРАТЬ
ТоварыНаСкладахОбороты.Регистратор.Номер КАК НомерДок,
ТоварыНаСкладахОбороты.Регистратор.Дата КАК ДатаДок,
ТоварыНаСкладахОбороты.Регистратор.Контрагент КАК Контрагент
// ... остальные поля
ИЗ ... Программное выполнение запроса (Пример на встроенном языке)
Процедура ПолучитьРегистраторовОборотов(Номенклатура, Склад, НачалоПериода, КонецПериода)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОбороты.Регистратор,
| ТоварыНаСкладахОбороты.Период,
| СУММА(ТоварыНаСкладахОбороты.КоличествоПриход) КАК Приход,
| СУММА(ТоварыНаСкладахОбороты.КоличествоРасход) КАК Расход
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.ОБОРОТЫ(
| ГраницаПериода,
| &НачалоПериода, &КонецПериода,
| Номенклатура = &Номенклатура И Склад = &Склад,
| Регистратор, Период
| ) КАК ТоварыНаСкладахОбороты
|СГРУППИРОВАТЬ ПО
| ТоварыНаСкладахОбороты.Регистратор,
| ТоварыНаСкладахОбороты.Период
|УПОРЯДОЧИТЬ ПО
| ТоварыНаСкладахОбороты.Период УБЫВ";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Запрос.УстановитьПараметр("Склад", Склад);
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
Результат = Запрос.Выполнить;
Выборка = Результат.Выбрать;
Пока Выборка.Следующий Цикл
// Выборка.Регистратор ౼ это Ссылка на документ (ДокументСсылка.РеализацияТоваровУслуг и т.д;)
Сообщить("Док: " + Выборка.Регистратор + " от " + Формат(Выборка.Период, "ДФ=dd.MM.yyyy ЧЧ:мм:сс") +
" Приход: " + Выборка.Приход + " Расход: " + Выборка.Расход);
КонецЦикла;
КонецПроцедуры Производительность и индексы
- Индексы регистра: Платформа автоматически создает индексы по измерениям. Указание условий отбора по измерениям (3-й параметр) позволяет использовать индексный поиск (Index Seek) вместо полного сканирования (Table Scan).
- Периодичность ГраницаПериода: Начиная с версий 8.3.15+, это рекомендуемый режим для получения движений без лишней агрегации по времени. Он работает быстрее, чем «Секунда», так как не требует нормализации времени до секунд.
- Избегайте лишних полей: В 4-м параметре перечисляйте только те поля, которые реально нужны для группировки. Каждое лишнее измерение увеличивает размер временной таблицы и время выполнения.
Резюме
- Для получения регистратора из оборотов обязательно добавьте
Регистратор(и желательноПериод) в четвертый параметр виртуальной таблицыОБОРОТЫ. - Используйте периодичность ГраницаПериода или Секунда, чтобы строки не сливались по дням/месяцам.
- Применяйте агрегатные функции (
СУММА) к ресурсам (Приход/Расход), так как происходит группировка. - Если нужны все строки документа (характеристики, серии, цены) — используйте виртуальную таблицу ДВИЖЕНИЯ с отбором по
Регистратор = &Ссылка. Это быстрее и функциональнее. - Для доступа к реквизитам документа (Номер, Дата, Контрагент) используйте точечную навигацию (
Регистратор.Номер) или LEFT JOIN с таблицей документов.
Грамотное использование виртуальных таблиц — залог быстрых и надежных отчетов и обработок в 1С:Предприятие 8.3.