Разработка и Конфигурация · 12 мин
Как сделать запрос к регистру сведений в 1С
Как сделать запрос к регистру сведений 1С: виртуальные таблицы СрезПоследних и СрезПервых, отборы, соединения, типовые ошибки и готовые примеры кода.
Регистр сведений в 1С хранит данные в разрезе измерений и, если регистр периодический, — с привязкой ко времени. Типовые примеры: курсы валют, цены номенклатуры, адреса контрагентов, штрихкоды. Запрос к такому регистру почти всегда строится вокруг вопроса: нужны все записи, только актуальные на дату или значения на конкретный момент в прошлом.
Главная особенность работы с регистрами сведений — виртуальные таблицы СрезПоследних и СрезПервых, которые доступны только для периодических регистров. Они позволяют одним запросом получить актуальные значения ресурсов без ручного поиска максимальной даты. Неправильное использование этих таблиц — самая частая причина медленных запросов и неверных данных в отчётах.
Ниже разобраны способы обращения к регистру сведений через язык запросов 1С: от простого выбора всех записей до срезов с отборами, соединений с другими таблицами и программной обработки результата. Примеры применимы к управляемым и обычным приложениям на платформе 8.3.
Структура регистра сведений и адресация в запросе
Перед написанием запроса важно понимать, из чего состоит таблица регистра. Измерения определяют разрезы хранения (например, Номенклатура, ТипЦен), ресурсы — сами значения (Цена), реквизиты — дополнительные данные, не участвующие в отборах. У периодического регистра добавляется служебное поле Период, а у регистра с режимом «Подчинение регистратору» — поле Регистратор.
В языке запросов физическая таблица регистра адресуется как РегистрСведений.ИмяРегистра. Например, запрос всех записей регистра курсов валют выглядит так:
ВЫБРАТЬ
КурсыВалют.Период,
КурсыВалют.Валюта,
КурсыВалют.Курс
ИЗ
РегистрСведений.КурсыВалют КАК КурсыВалют
Такой запрос к физической таблице возвращает все записи без исключения. Для регистра с историей изменений за несколько лет это могут быть сотни тысяч строк, поэтому чтение физической таблицы целиком без отборов почти всегда является ошибкой проектирования.
СрезПоследних: получение актуальных значений на дату
Виртуальная таблица СрезПоследних возвращает для каждой комбинации измерений последнюю по времени запись, не превышающую указанную дату. Это стандартный способ узнать, например, цену товара или курс валюты на конкретное число:
ВЫБРАТЬ
КурсыСрез.Валюта,
КурсыСрез.Курс
ИЗ
РегистрСведений.КурсыВалют.СрезПоследних(&Дата, ) КАК КурсыСрез
Первый параметр виртуальной таблицы — дата среза. Если её не указать, срез строится на текущую дату сеанса, что в серверном коде часто приводит к неожиданным результатам: запрос, отлаженный вчера, сегодня вернёт другие данные. Всегда передавайте дату явно через параметр.
Если параметр даты не задан и регистр содержит записи будущими датами (например, запланированное изменение цен), срез без даты покажет будущие значения. Это типичный источник ошибок в отчётах, которые «вчера считали правильно».
Отборы в виртуальных таблицах: параметры против секции ГДЕ
Второй параметр виртуальной таблицы — условие отбора по измерениям. Ключевое правило: отбор по измерениям должен задаваться именно здесь, а не в секции ГДЕ основного запроса. Разница принципиальна для производительности.
ВЫБРАТЬ
ЦеныСрез.Номенклатура,
ЦеныСрез.Цена
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
&Дата,
Номенклатура В (&СписокНоменклатуры)
И ТипЦен = &ТипЦен) КАК ЦеныСрез
Когда условие передано в параметры виртуальной таблицы, платформа сначала вычисляет срез только для нужных измерений, а затем выполняет основной запрос. Если то же условие написать в секции ГДЕ, платформа построит срез по всему регистру и лишь потом отфильтрует результат. На регистре в несколько миллионов записей разница во времени выполнения — от секунд до минут.
Отбор по ресурсам и реквизитам (например, «Цена > 1000») в параметрах виртуальной таблицы недоступен — такие условия законно размещаются в секции ГДЕ, поскольку фильтруют уже вычисленный срез.
СрезПервых и работа с периодом
Виртуальная таблица СрезПервых работает зеркально: возвращает самую раннюю запись для каждой комбинации измерений начиная с указанной даты. Типовой сценарий — узнать, когда и какое значение впервые вступило в силу после определённого момента, например первую цену после начала года.
Синтаксис идентичен СрезПоследних: первый параметр — дата, второй — отбор по измерениям. Учитывайте, что СрезПервых используется заметно реже, и в типовых конфигурациях многие задачи, которые кажутся подходящими для него, решаются через обычный запрос к физической таблице с упорядочиванием по периоду.
Если нужна не одна актуальная запись, а история изменений значения за период, виртуальные таблицы не подходят. В этом случае запрос строится к физической таблице с отбором по периоду в секции ГДЕ:
ВЫБРАТЬ
КурсыВалют.Период,
КурсыВалют.Курс
ИЗ
РегистрСведений.КурсыВалют КАК КурсыВалют
ГДЕ
КурсыВалют.Валюта = &Валюта
И КурсыВалют.Период МЕЖДУ &НачалоПериода И &КонецПериода
УПОРЯДОЧИТЬ ПО
КурсыВалют.Период
Соединение регистра сведений с другими таблицами
На практике срез регистра сведений почти всегда соединяется со справочником или таблицей документа — например, чтобы подтянуть цены к списку товаров. Здесь важны два момента: тип соединения и дата среза.
Используйте ЛЕВОЕ СОЕДИНЕНИЕ от справочника к срезу, если нужно показать все товары, включая те, для которых цена не задана. ВНУТРЕННЕЕ соединение скроет позиции без цены, что часто воспринимается пользователями как «пропавшие товары». После левого соединения отсутствующие значения ресурсов будут равны NULL — обрабатывайте это функцией ЕСТЬNULL:
ВЫБРАТЬ
Товары.Ссылка КАК Номенклатура,
ЕСТЬNULL(ЦеныСрез.Цена, 0) КАК Цена
ИЗ
Справочник.Номенклатура КАК Товары
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ) КАК ЦеныСрез
ПО Товары.Ссылка = ЦеныСрез.Номенклатура
Когда запрос строится к табличной части документа и цены нужны на дату каждого документа, возникает задача «среза на разные даты». Стандартное решение — соединение с физической таблицей регистра с группировкой по максимальному периоду, либо использование механизма, где дата среза берётся из полей соединяемой таблицы. Учтите: параметр виртуальной таблицы не может ссылаться на поле другой таблицы запроса, поэтому универсальный СрезПоследних здесь не работает, и запрос усложняется.
Если в отчёте на СКД срез нужен на дату каждого документа, а не на одну фиксированную дату, часто проще вынести получение значений в собственный набор данных-запрос с группировкой МАКСИМУМ(Период) и последующим соединением, чем пытаться обойти ограничение виртуальной таблицы.
Программное выполнение запроса и обработка результата
Текст запроса выполняется через объект Запрос с установкой параметров. Типовой фрагмент кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЦеныСрез.Номенклатура,
| ЦеныСрез.Цена
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ТипЦен = &ТипЦен) КАК ЦеныСрез";
Запрос.УстановитьПараметр("Дата", КонецДня(ДатаОтчета));
Запрос.УстановитьПараметр("ТипЦен", ТипЦен);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// обработка строки
КонецЦикла;
Обратите внимание на дату среза: для получения значений на конкретный день часто передают КонецДня(), иначе записи, сделанные в течение дня позже указанного времени, в срез не попадут. Если регистр подчинён регистратору и важна точность до документа, вместо даты передают момент времени или границу.
Для проверки результата без написания обработки используйте консоль запросов: она позволяет интерактивно менять параметры и сразу видеть, какие записи возвращает срез. Это самый быстрый способ убедиться, что дата и отборы заданы корректно.
- 1Определите, периодический ли регистр и нужна ли история или только актуальные значения
- 2Для актуальных значений используйте СрезПоследних с явным параметром даты
- 3Передайте отбор по измерениям во второй параметр виртуальной таблицы
- 4При соединении со справочником выберите ЛЕВОЕ СОЕДИНЕНИЕ и обработайте NULL через ЕСТЬNULL
- 5Проверьте результат в консоли запросов на тестовых данных и на граничных датах
Типичные ошибки и как их избежать
Первая группа ошибок связана с логикой: срез без даты, неверная граница периода (начало дня вместо конца), забытый ЕСТЬNULL после левого соединения. Эти ошибки не вызывают падения кода — они дают неправильные цифры, которые долго остаются незамеченными.
Вторая группа — производительность: отбор по измерениям в секции ГДЕ, срез по всему регистру при необходимости нескольких записей, соединение с виртуальной таблицей без отборов внутри сложного пакетного запроса. Диагностируется через замер времени выполнения и план запроса в технологическом журнале.
Третья группа — права доступа. Если у пользователя нет прав на регистр сведений, запрос в привилегированном режиме вернёт данные, а в обычном — ошибку или пустой результат в зависимости от контекста. Проверяйте отчёты под реальной ролью пользователя, а не только под полными правами.
Проверка результата и выбор подхода
После написания запроса проверьте его на граничных ситуациях: дата раньше первой записи регистра (срез должен быть пустым, а не ошибочным), дата между двумя записями, отбор по измерению, которого нет в регистре. Консоль запросов позволяет прогнать эти сценарии за пару минут.
Выбор между физической таблицей и виртуальными определяется задачей. Нужна история изменений — физическая таблица с отбором по периоду. Нужно актуальное значение на дату — СрезПоследних. Нужно первое значение после даты — СрезПервых. Нужны значения на разные даты для разных строк — группировка по максимальному периоду с соединением.
Как проверить результат
Не превышает число комбинаций измерений в отборе
Строк больше, чем ожидалось — вероятно, срез взят без даты или отбор не сработал
Совпадают с последней записью в карточке регистра на дату среза
Показаны будущие или устаревшие значения — проверьте параметр даты
Запрос с отбором в параметрах выполняется быстро даже на большом регистре
Заметная задержка — отбор, скорее всего, стоит в секции ГДЕ
Что важно запомнить
Актуальные значения периодического регистра получайте через СрезПоследних с явной датой, отборы по измерениям передавайте в параметры виртуальной таблицы, при соединении со справочниками используйте ЛЕВОЕ СОЕДИНЕНИЕ и ЕСТЬNULL, а результат проверяйте на граничных датах в консоли запросов.
Частые вопросы
Чем СрезПоследних отличается от СрезПервых?
СрезПоследних возвращает самую позднюю запись на дату или раньше неё, СрезПервых — самую раннюю запись начиная с даты и позже. Первый отвечает на вопрос «какое значение действовало на дату», второй — «какое значение появилось после даты».
Можно ли сделать срез на дату каждого документа в одном запросе?
Напрямую через виртуальную таблицу — нет, её параметр даты не может ссылаться на поле другой таблицы. Задача решается соединением с физической таблицей регистра и группировкой МАКСИМУМ(Период) с условием, что период не превышает дату документа, с последующим соединением для получения ресурсов.
Почему срез возвращает пустой результат, хотя записи в регистре есть?
Чаще всего дата среза раньше первой записи регистра или отбор по измерениям не совпадает с реальными значениями (например, передана пустая ссылка). Проверьте запрос в консоли запросов, временно убрав отборы.
Что быстрее: запрос или метод ПолучитьПоследнее менеджера регистра?
Для одного значения ПолучитьПоследнее проще и не медленнее. Для списка измерений (например, цен тысячи товаров) запрос со срезом выполняется одним обращением к базе и значительно быстрее, чем цикл с вызовом метода для каждой позиции.
Нужны ли индексы для ускорения среза?
Платформа автоматически индексирует измерения регистра сведений, поэтому дополнительных действий обычно не требуется. Если запрос медленный, сначала проверьте, что отборы стоят в параметрах виртуальной таблицы, — это решает большинство проблем без изменения структуры метаданных.