Работа с регистрами сведений является одной из фундаментальных задач при разработке конфигураций на платформе 1С:Предприятие 8. Эти объекты предназначены для хранения статической или медленно меняющейся информации, такой как курсы валют, номенклатурные группы или настройки системы. Понимание того, как корректно извлечь данные из них, критически важно для создания эффективного кода.
В отличие от документов, которые фиксируют хозяйственные операции во времени, регистры сведений часто содержат актуальные состояния объектов на текущий момент или на определенную дату. Неправильное построение запроса может привести к получению дублирующихся записей или, что хуже, к существенному падению производительности системы при больших объемах данных. В этой статье мы разберем все нюансы формирования выборки.
Начнем с базового синтаксиса и структуры, которую платформа ожидает от разработчика. Вы увидите, что работа с этими объектами имеет свои особенности, связанные с наличием измерений, ресурсов и реквизитов. Грамотное использование этих элементов позволяет писать код, который легко читать и поддерживать в будущем.
Структура регистра и базовый синтаксис запроса
Прежде чем писать код, необходимо четко представлять физическую структуру объекта. Регистр сведений состоит из измерений, которые формируют уникальность записи, и ресурсов, содержащих полезные данные. Также могут присутствовать реквизиты, которые не участвуют в уникальности, но хранят дополнительную информацию.
При формировании текста запроса вы обращаетесь к таблице регистра как к обычному источнику данных. Однако Простой запрос выглядит следующим образом:
ВЫБРАТЬ
РегистрСведений.КурсыВалют.Валюта КАК Валюта,
РегистрСведений.КурсыВалют.Курс КАК Курс
ИЗ
РегистрСведений.КурсыВалют
Такой запрос вернет все записи, когда-либо введенные в систему. Это допустимо для небольших справочников, но опасно для объемных данных. Измерения регистра играют роль ключей, по которым происходит группировка и поиск. Если в регистре включен контроль уникальности по измерениям, база данных гарантирует, что комбинация значений измерений не повторится (в рамках одного периода или без него).
Всегда указывайте псевдонимы для полей в запросе (КАК..), это делает дальнейшую работу с результатом в коде 1С более понятной изащищает от ошибок при изменении метаданных.
Стоит отметить, что имена полей в запросе должны точно совпадать с именами в конфигураторе. Регистр сведений может быть периодическим или непериодическим. Это свойство определяет, нужно ли вам учитывать временную шкалу при выборке данных. В непериодических регистрах хранится просто список значений, актуальный на текущий момент.
Работа с периодическими регистрами сведений
Наиболее сложный и интересный сценарий возникает при работе с периодическими регистрами. В таких объектах одна и та же комбинация измерений может встречаться многократно, но с разными датами и временем. Примером служат курсы валют, которые меняются ежедневно.
Если вы сделаете обычный запрос к периодическому регистру без указания даты, система вернет все исторические данные. Это редко бывает нужно. Чаще всего требуется получить состояние объекта на конкретный момент времени. Для этого в 1С существует понятие виртуальных таблиц.
⚠️ Внимание: Никогда не используйте прямое обращение к физической таблице периодического регистра (через точку) для получения актуальных данных на дату. Это приведет к ручной фильтрации и потере производительности. Всегда используйте срез.
Виртуальная таблица «СрезПоследних» позволяет получить последние записи по каждому уникальному набору измерений на указанную дату. Синтаксис вызова такой таблицы требует указания параметра даты в круглых скобках после имени регистра.
ВЫБРАТЬ
СрезПоследних.Валюта,
СрезПоследних.Курс
ИЗ
РегистрСведений.КурсыВалют.СрезПоследних(&ДатаЗапроса) КАК СрезПоследних
Здесь &ДатаЗапроса — это параметр, передаваемый в запрос. Платформа сама найдет последние записи, дата которых меньше или равна указанной. Это оптимизированный механизм, который использует специальные индексы базы данных для ускорения выборки.
Использование отборов и параметров в запросе
В реальных задачах редко требуется выгружать весь регистр целиком. Обычно нас интересуют данные по конкретному контрагенту, складу или валюте. Для ограничения выборки используется конструкция ГДЕ. Эффективный отбор — залог быстродействия вашей программы.
Отбор следует применять как можно раньше, чтобы база данных не перебирала лишние строки. Если вы используете виртуальные таблицы срезов, отбор применяется уже к результату среза. Это важно учитывать при планировании логики.
- 🔍 Используйте параметры запроса вместо подстановки значений прямо в текст, это позволяет переиспользовать текст запроса.
- 🚀 Старайтесь включать в отбор поля, по которым в базе данных построены индексы (обычно это измерения).
- ⚙️ Избегайте функций в левой части условий отбора (например,
ГОД(Период) = 2023), так как это отключает использование индексов.
Рассмотрим пример, где мы выбираем курсы только для доллара и евро на текущую дату. Здесь мы комбинируем виртуальную таблицу и оператор В для списка значений.
ВЫБРАТЬ
СрезПоследних.Валюта,
СрезПоследних.Курс
ИЗ
РегистрСведений.КурсыВалют.СрезПоследних(&ДатаЗапроса) КАК СрезПоследних
ГДЕ
СрезПоследних.Валюта В (&Валюта1, &Валюта2)
Параметры запроса передаются через объект Запрос в коде 1С перед выполнением. Такой подход делает код гибким. Вы можете один раз написать текст запроса, а менять только значения параметров в цикле или в зависимости от действий пользователя.
☑️ Оптимизация отбора
Соединение регистров с другими таблицами
Часто данные из регистра сведений имеют смысл только в связке с другими объектами метаданных. Например, чтобы показать название валюты, а не только её код, нужно соединить регистр курсов со справочником валют. Для этого используются операторы соединения ЛЕВОЕ СОЕДИНЕНИЕ или ВНУТРЕННЕЕ СОЕДИНЕНИЕ.
Левое соединение гарантирует, что все записи из левой таблицы (регистра) попадут в результат, даже если для них не найдется соответствия в правой таблице (справочнике). Это полезно, если в регистре могли остаться ссылки на удаленные элементы.
| Тип соединения | Описание поведения | Когда применять |
|---|---|---|
| ЛЕВОЕ СОЕДИНЕНИЕ | Все строки слева + совпадения справа | Когда нужны все записи регистра, даже без описания |
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ | Только строки, где есть совпадение в обеих таблицах | Когда нужны только корректные ссылки на справочники |
| ПОЛНОЕ СОЕДИНЕНИЕ | Все строки из обеих таблиц | Редко, для анализа расхождений в данных |
Пример соединения для получения полного названия валюты:
ВЫБРАТЬ
СрезПоследних.Валюта КАК КодВалюты,
СправочникВалют.Наименование КАК Название
ИЗ
РегистрСведений.КурсыВалют.СрезПоследних(&ДатаЗапроса) КАК СрезПоследних
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Валюты КАК СправочникВалюты
ПО СрезПоследних.Валюта = СправочникВалюты.Ссылка
При использовании соединений важно следить за дублированием строк. Если в справочнике по какой-то причине окажется два элемента с одинаковой ссылкой (что невозможно для справочников, но возможно для других таблиц), результат запроса размножится. В случае со справочниками это безопасно, так как ссылка уникальна.
Агрегация данных и группировка
Иногда требуется не просто вывести список, а получить сводную информацию. Например, посчитать среднюю цену по регистру сведений о ценах номенклатуры или найти максимальный курс за период. Для этого служат агрегатные функции: СУММА, КОЛИЧЕСТВО, МИНИМУМ, МАКСИМУМ, СРЕДНЕЕ.
При использовании агрегатных функций все неагрегированные поля должны быть указаны в конструкции ГРУППИРОВКА ПО. Это строгое правило языка запросов 1С, нарушение которого приведет к ошибке синтаксиса.
⚠️ Внимание: Агрегация по периодическому регистру без использования срезов может дать неверный результат, так как в выборку попадут все исторические записи. Сначала делайте срез, потом агрегируйте.
Рассмотрим задачу: нужно узнать, сколько уникальных валют имеют курс выше 50 рублей на текущую дату. Здесь мы используем функцию КОЛИЧЕСТВО(РАЗЛИЧНЫЕ..).
ВЫБРАТЬ
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ СрезПоследних.Валюта) КАК КоличествоВалют
ИЗ
РегистрСведений.КурсыВалют.СрезПоследних(&ДатаЗапроса) КАК СрезПоследних
ГДЕ
СрезПоследних.Курс > 50
Группировка позволяет разбить результат на категории. Например, сгруппировать цены по видам номенклатуры. В этом случае в секции ГРУППИРОВКА ПО указывается измерение или реквизит, по которому происходит деление. Это мощный инструмент для построения отчетов непосредственно на уровне запроса.
Особенность функции СУММА
Если в выборке нет ни одной строки, удовлетворяющей условию, функция СУММА вернет NULL, а не 0. Всегда используйте функцию ЕСТЬNULL() для замены NULL на 0, если планируете арифметические операции с результатом.
Обработка результатов запроса в коде 1С
После того как текст запроса сформирован и выполнен, данные попадают в объект ВыборкаИзРезультатаЗапроса. Обработка этих данных обычно происходит в цикле. Важно правильно извлекать значения полей, обращаясь к ним по именам, указанным в секции ВЫБРАТЬ.
Существует два основных способа обхода результатов: через цикл Для каждого и через метод Следующий(). Первый способ более нагляден и предпочтителен в большинстве случаев, так как автоматически управляет курсором выборки.
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщение = "Валюта: " + Выборка.КодВалюты + ", Курс: " + Выборка.Курс;
Сообщить(Сообщение);
КонецЦикла;
Если запрос вернул пустой результат, цикл просто не выполнится ни разу. Это нормальная ситуация, которую не всегда нужно считать ошибкой. Однако, если вы ожидаете строго одну запись (например, поиск конкретного элемента по уникальному коду), стоит проверить количество строк через метод Количество() у объекта Результат.
Используйте выборку только для чтения данных. Попытка изменить данные регистра непосредственно через выборку запроса невозможна — для записи используйте объект РегистрСведений.МенеджерЗаписи или набор записей.
Частые ошибки и оптимизация производительности
Разработчики часто допускают типичные ошибки, которые превращают быстрый запрос в "тормоз". Самая распространенная из них — игнорирование индексов при отборе. Если вы фильтруете по полю, которое не является измерением или не проиндексировано, базе данных придется сканировать всю таблицю.
Еще одна ошибка — использование вложенных запросов там, где достаточно соединения. Вложенные запросы могут быть полезны для сложной логики, но часто их можно заменить более производительными JOIN-операциями. Также стоит избегать выбора всех полей звездочкой (*), выбирайте только то, что действительно нужно.
- 🛑 Не делайте запросы внутри циклов кода 1С. Лучше собрать все необходимые параметры в массив и сделать один большой запрос с условием
В. - 📉 Избегайте преобразования типов данных в условиях отбора, это ломает использование индексов.
- ⏱ Тестируйте запросы на производственной копии базы с реальным объемом данных, а не на пустой учебной базе.
Для анализа скорости выполнения запроса используйте встроенную обработку "Консоль запросов". Она показывает план выполнения и время затраченное на каждый этап. Если вы видите полное сканирование таблицы (Table Scan) там, где ожидается поиск по индексу (Index Seek), значит, запрос составлен неоптимально.
⚠️ Внимание: Интерфейс и возможности консоли запросов могут отличаться в разных версиях платформы 1С. Если вы не находите какой-то пункт меню, сверьтесь со справкой по вашей конкретной версии конфигуратора.
FAQ: Часто задаваемые вопросы
В чем разница между СрезПоследних и СрезПервых?
СрезПоследних возвращает записи с максимальной датой, которая меньше или равна указанной (история до момента). СрезПервых возвращает записи с минимальной датой, которая больше или равна указанной (будущее от момента). Выбор зависит от логики вашего бизнеса.
Можно ли записывать данные в регистр сведений через запрос?
Нет, язык запросов 1С предназначен только для чтения данных (оператор ВЫБРАТЬ). Для записи, изменения или удаления данных необходимо использовать объектный метод в коде 1С, например, РегистрСведений.СоздатьМенеджерЗаписи().
Что делать, если запрос возвращает дубликаты записей?
Проверьте, по каким полям вы делаете соединение. Возможно, вы соединяете с таблицей, где одному элементу соответствует несколько записей (один ко многим). Используйте ключевое слово РАЗЛИЧНЫЕ в секции ВЫБРАТЬ или пересмотрите логику соединения.
Как передать список значений в параметр запроса?
Вы можете передать в параметр массив, таблицу значений или список значений. В тексте запроса используйте оператор В. Например: ГДЕ Поле В (&ПараметрСписка). Платформа автоматически раскроет список.
Почему запрос работает медленно только вечером?
Возможно, в это время выполняются тяжелые регламентные задания или закрытие дня, которые блокируют таблицы или нагружают дисковую подсистему. Проверьте журнал регистрации и блокировки СУБД в это время.