К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как сделать выборку из регистра сведений в 1С

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

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

Выбор способа зависит от задачи. Если нужны данные для отчёта, обработки или массовой операции — используйте запрос: он выполняется на сервере СУБД и работает быстрее. Если нужно прочитать одну конкретную запись по известному ключу или обойти записи с возможностью изменения — подойдут объектные методы Выбрать() и СоздатьНаборЗаписей().

Как устроен регистр сведений и что влияет на выборку

Перед написанием кода определите три свойства регистра, потому что от них зависит текст запроса. Первое — периодичность: непериодический регистр хранит плоскую таблицу, а периодический добавляет поле Период и виртуальные таблицы СрезПоследних и СрезПервых. Второе — режим подчинения регистратору: подчинённый регистр заполняется движениями документов, и в нём появляется поле Регистратор. Третье — состав измерений: именно по ним строится отбор.

Измерения — это ключи записи (например, «Номенклатура» и «ТипЦен»), ресурсы — хранимые значения (например, «Цена»), реквизиты — дополнительные данные, не участвующие в ключе. Условия отбора по измерениям выполняются быстро, так как по ним построены индексы. Отбор по ресурсам и реквизитам может привести к полному сканированию таблицы на больших объёмах.

Выборка запросом с отбором по условиям

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

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Цены.Номенклатура,

| Цены.Цена

|ИЗ

| РегистрСведений.ЦеныНоменклатуры КАК Цены

|ГДЕ

| Цены.ТипЦен = &ТипЦен";

Запрос.УстановитьПараметр("ТипЦен", ТипЦенРозничная);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

// обработка строки: Выборка.Номенклатура, Выборка.Цена

КонецЦикла;

Параметры всегда передавайте через УстановитьПараметр(), а не конкатенацией строк — это защищает от ошибок с типами данных и от внедрения произвольного текста в запрос. Несколько условий объединяйте операторами И / ИЛИ, а для списка значений используйте оператор В (&Список) с параметром типа массив или список значений.

Если результат нужен для заполнения табличной части или дальнейшей обработки как коллекции, удобнее выгрузить его: ТаблицаРезультата = Запрос.Выполнить().Выгрузить();. Таблицу значений можно сортировать, сворачивать и искать в ней методом Найти() без повторных обращений к базе.

Выборка актуальных значений через СрезПоследних

Частая задача — получить значение, действующее на конкретную дату: текущий курс валюты, цену на дату документа, ФИО сотрудника с учётом переименования. Для этого у периодического регистра есть виртуальная таблица СрезПоследних, принимающая два параметра: дату среза и условие отбора.

Запрос.Текст =

"ВЫБРАТЬ

| Курсы.Валюта,

| Курсы.Курс

|ИЗ

| РегистрСведений.КурсыВалют.СрезПоследних(&ДатаСреза, Валюта = &Валюта) КАК Курсы";

Запрос.УстановитьПараметр("ДатаСреза", ТекущаяДатаСеанса());

Запрос.УстановитьПараметр("Валюта", ВалютаUSD);

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

Объектные методы: Выбрать, набор записей и чтение одной записи

Метод РегистрыСведений.ИмяРегистра.Выбрать(Отбор) возвращает выборку записей, которую обходят циклом Пока Выборка.Следующий(). Отбор задаётся структурой, где ключ — имя измерения. Такая выборка доступна и для чтения, и для модификации, если использовать Выбрать() с последующим изменением полей записи.

Для чтения и изменения группы записей надёжнее использовать набор записей: создать его методом СоздатьНаборЗаписей(), установить отбор по измерениям, выполнить Прочитать(), изменить строки и записать методом Записать(). Набор записей работает как единая транзакция — либо записывается весь набор, либо ничего.

Если известны все значения измерений и нужна ровно одна запись, используйте Получить(Отбор) у менеджера регистра или СоздатьМенеджерЗаписи() с заполненными измерениями и методом Прочитать(). После чтения проверяйте МенеджерЗаписи.Выбран() — если запись не найдена, обращение к её полям даст пустые значения без ошибки, что легко пропустить.

Сравнение способов выборки

Запрос с ГДЕ

Подходит для отчётов, обработок и массовых операций; самый быстрый вариант, но результат доступен только для чтения.

СрезПоследних / СрезПервых

Единственный корректный способ получить актуальное значение периодического регистра на дату; требует явной даты среза.

Выбрать() с отбором

Обход записей с возможностью модификации; медленнее запроса на больших объёмах, оправдан при построчной записи.

Набор записей

Чтение и перезапись группы записей целиком в одной транзакции; не подходит для простого чтения данных.

Выборка из регистра, подчинённого регистратору

Если регистр подчинён регистратору, записи создаются только движениями документов, и ручное изменение набора в обход документа нарушит логику учёта. Для чтения таких данных используйте обычный запрос с отбором по измерениям или по регистратору: ГДЕ Движения.Регистратор = &Документ.

Типичный сценарий — получить движения конкретного документа. Проще всего это сделать через набор записей: установить отбор по регистратору и прочитать. Альтернатива — обратиться к коллекции движений документа ДокументОбъект.Движения.ИмяРегистра в момент проведения, если данные нужны внутри обработки проведения.

Проверка результата и производительность

После выполнения запроса проверяйте, не пуст ли результат: Результат = Запрос.Выполнить(); Если Результат.Пустой() Тогда .... Это избавляет от лишнего цикла и позволяет явно обработать ситуацию «данных нет» — например, подставить значение по умолчанию или сообщить пользователю.

Для соединений регистра со справочниками следите за порядком таблиц и условиями соединения: левое соединение от виртуальной таблицы среза к справочнику обычно работает быстрее, чем наоборот. На больших регистрах избегайте выборки всех записей без отбора — ограничивайте результат параметрами и выбирайте только нужные поля вместо ВЫБРАТЬ *.

Контрольные точки

Как проверить результат

Пустота результата
Норма

Результат.Пустой() обработан отдельной веткой логики

Тревожный признак

Цикл молча не выполняется, и ошибка заметна только в итоговых данных

Дата среза
Норма

СрезПоследних получает дату документа или сеанса

Тревожный признак

Срез без даты возвращает будущие или неожиданные значения

Тип параметра
Норма

Параметр передан с тем же типом, что и измерение (ссылка нужного вида)

Тревожный признак

Параметр-строка вместо ссылки даёт пустую выборку без ошибки

Количество строк
Норма

Число записей соответствует ожиданиям по данным в пользовательском режиме

Тревожный признак

Запрос вернул дубликаты из-за лишнего соединения

Типичные ошибки при выборке из регистра сведений

Самая распространённая ошибка — получение актуальных значений не через СрезПоследних, а простым запросом с сортировкой по периоду и взятием первой строки. Такой код медленнее и часто возвращает неверные данные, когда по одной комбинации измерений несколько записей с одинаковым периодом.

Вторая группа ошибок связана с параметрами: передача строки вместо ссылки, незаполненная дата среза, отбор по реквизиту вместо измерения. Все они не вызывают исключения — запрос просто возвращает пустой результат, и дефект проявляется далеко от места ошибки. Проверяйте параметры перед выполнением и логируйте пустые результаты в ответственных операциях.

Типичные ошибки
01
Отбор по реквизиту вместо измерения — индекс не используется, запрос сканирует всю таблицу
02
СрезПоследних без даты — возвращаются значения на максимальную дату, а не на дату документа
03
Обращение к полям менеджера записи без проверки Выбран() — пустые значения уходят дальше по алгоритму
04
Построчная запись через Выбрать() вместо набора записей — потеря производительности и частичная запись при сбое
05
Конкатенация значений в текст запроса — ошибки типов и риск некорректного запроса
Итог

Что важно запомнить

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

Вопросы и ответы

Чем выборка запросом отличается от метода Выбрать()?

Запрос выполняется целиком на сервере СУБД и возвращает результат только для чтения — это быстрее и предпочтительнее для отчётов и обработок. Метод Выбрать() возвращает объектные записи, которые можно изменять и записывать, но построчная работа медленнее на больших объёмах.

Как получить последнее значение по каждому измерению?

Используйте виртуальную таблицу СрезПоследних с датой среза: она возвращает по одной записи на каждую комбинацию измерений. Если нужен срез по группе элементов, передайте условие В (&Список) вторым параметром виртуальной таблицы.

Почему запрос возвращает пустой результат, хотя данные в регистре есть?

Чаще всего причина в несовпадении типов: параметр содержит строку или код вместо ссылки, либо ссылку другого справочника. Также проверьте дату среза в СрезПоследних — если записи позже указанной даты, они не попадут в результат.

Можно ли отбирать записи по ресурсу, а не по измерению?

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

Как выбрать записи за определённый интервал дат?

Для периодического регистра добавьте в запрос условие ГДЕ Период МЕЖДУ &НачалоПериода И &КонецПериода. Если нужны не все записи интервала, а значения на его границы, используйте СрезПервых для начала и СрезПоследних для конца периода.

Что быстрее: запрос или обход через набор записей?

Для чтения — всегда запрос: он не создаёт объектов в памяти и выполняется одним обращением к базе. Набор записей оправдан только когда данные нужно изменить и записать обратно, потому что он обеспечивает целостность записи группы строк.