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