Работа с регистрами в 1С:Предприятие часто требует точного определения типа регистратора — особенно когда речь идет о сложных отчетах, обработках или интеграциях. Ошибка в идентификации может привести к некорректным данным, падению производительности или даже сбоям в работе системы. Эта статья поможет разобраться, как программно определить, к какому типу относится регистратор: регистру накопления, регистру сведений или регистру бухгалтерии — прямо в тексте запроса.
Мы рассмотрим не только стандартные методы через Метаданные и ТипЗначения, но и практические примеры с учетом особенностей разных версий платформы. Особое внимание уделим типичным ошибкам, которые допускают разработчики при работе с виртуальными таблицами и динамическими запросами. Если вы когда-нибудь сталкивались с ситуацией, когда запрос возвращает данные "не оттуда" — эта инструкция для вас.
Зачем нужно определять тип регистратора в запросе?
На первый взгляд, тип регистратора может показаться вторичным параметром — ведь главное, чтобы данные были актуальными. Однако на практике это критично в нескольких сценариях:
- 🔄 Оптимизация запросов: разные типы регистров имеют различные механизмы индексации. Например, регистры бухгалтерии часто требуют дополнительных связей с планом счетов, что замедляет выполнение.
- 📊 Построение универсальных отчетов: если ваш отчет работает с несколькими типами регистров, логика формирования данных будет отличаться (например, остатки vs обороты).
- 🔧 Отладка и поддержка: при анализе чужого кода или исправлении ошибок быстрое определение типа регистратора экономит часы работы.
- 🤖 Автоматизация обменов: при интеграции с внешними системами (например, через REST API или COM-соединение) тип регистратора может влиять на формат передаваемых данных.
Более того, в некоторых случаях неверное определение типа регистратора может привести к "тихим" ошибкам — когда запрос выполняется без видимых сбоев, но возвращает неверные данные. Например, если вы пытаетесь получить остатки из регистра сведений, используя методы для регистра накопления, система не выдаст ошибку, но результаты будут бессмысленными.
Способ 1: Использование функции ТипЗначения()
Самый прямолинейный метод — проверка типа значения через встроенную функцию ТипЗначения(). Этот подход работает в большинстве версий платформы (начиная с 8.2) и не требует глубоких знаний метаданных. Пример кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Регистратор.Ссылка КАК Ссылка,
| ТИПЗНАЧЕНИЯ(Регистратор.Ссылка) КАК ТипРегистратора
|ИЗ
| РегистрНакопления.ОстаткиТоваров КАК Регистратор
|ГДЕ
| Регистратор.Период МЕЖДУ &НачалоПериода И &КонецПериода";
Результат = Запрос.Выполнить();
В результате выполнения этого запроса поле ТипРегистратора будет содержать строку вида:
СправочникСсылка.ДокументПоступлениеТоваров — если регистратор является документом, или
ДокументСсылка.РеализацияТоваров — если это документ другого типа.
⚠️ Внимание: Функция ТипЗначения() возвращает тип ссылки на регистратор, а не тип самого регистра. Если вам нужно определить, к какому регистру (накопления, сведений или бухгалтерии) относится запись — этот метод не подходит.
Для более точной идентификации типа регистра (а не регистратора) потребуется комбинировать этот подход с другими методами, о которых пойдет речь далее.
Способ 2: Анализ метаданных через системные таблицы
Если вам необходимо определить, к какому типу регистра относится текущая виртуальная таблица, можно воспользоваться системными таблицами метаданных. Этот метод универсален и работает во всех конфигурациях на базе 1С:Предприятие 8.
Пример запроса для определения типа регистра по его имени:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Метаданные.Имя КАК ИмяРегистра,
| ВЫРАЗИТЬ(Метаданные.Тип КАК Строка) КАК ТипРегистра
|ИЗ
| v8:Метаданные КАК Метаданные
|ГДЕ
| Метаданные.Имя = &ИмяРегистра";
Запрос.УстановитьПараметр("ИмяРегистра", "ОстаткиТоваров");
Результат = Запрос.Выполнить();
В поле ТипРегистра вы получите одно из значений:
"РегистрНакопления", "РегистрСведений" или "РегистрБухгалтерии".
| Тип регистра | Возвращаемое значение | Пример использования |
|---|---|---|
| Регистр накопления | "РегистрНакопления" |
Учет остатков товаров, денежных средств |
| Регистр сведений | "РегистрСведений" |
Хранение справочной информации (курсы валют, цены) |
| Регистр бухгалтерии | "РегистрБухгалтерии" |
Бухгалтерские проводки, обороты по счетам |
| Регистр расчета | "РегистрРасчета" |
Начисление зарплаты, расчет налогов |
Этот метод особенно полезен, если вы пишете универсальный код, который должен работать с разными конфигурациями. Например, при разработке внешних отчетов или обработок для тиражных решений.
Если вам нужно получить список всех регистров в базе с их типами, замените условие ГДЕ на ГДЕ Метаданные.Тип В (&Типы) и передайте массив с типами: Новый Массив("РегистрНакопления", "РегистрСведений")
Способ 3: Проверка через конструктор запроса (для визуального анализа)
Если вы работаете в режиме 1С:Предприятие (не в конфигураторе), и вам нужно быстро определить тип регистратора без написания кода, можно воспользоваться конструктором запросов. Этот метод не требует программирования и подходит для аналитиков или пользователей с ограниченными правами.
Инструкция:
- Откройте любой отчет или обработку, где есть возможность построить запрос (например, "Универсальный отчет").
- В конструкторе запроса добавьте таблицу регистра, тип которого нужно определить (например,
РегистрНакопления.ОстаткиТоваров). - В списке доступных полей найдите поле
Регистратори посмотрите, какой тип данных у него указан в подсказке. - Если тип —
ДокументСсылка.ИмяДокумента, значит регистратором является документ. ЕслиСправочникСсылка.ИмяСправочника— справочник.
Этот способ не дает информации о типе регистра (накопления/сведений/бухгалтерии), но позволяет быстро идентифицировать тип регистратора (документ, справочник и т.д.).
⚠️ Внимание: В некоторых конфигурациях (например, в 1С:ERP или 1С:КА) регистраторами могут быть не только документы, но и задачи, события или другие объекты. В этом случае тип ссылки будет отличаться (например, ЗадачаСсылка.ПроизводственнаяЗадача).
Способ 4: Программное определение через объект Метаданные
Для разработчиков, которые пишут код на встроенном языке, самый надежный способ — работа с объектом Метаданные. Этот метод позволяет получить полную информацию о регистре, включая его тип, состав измерений и ресурсов.
Пример кода:
// Получаем объект метаданных регистра по имени
Регистр = Метаданные.РегистрыНакопления.ОстаткиТоваров;
// Проверяем тип регистратора (документ, справочник и т.д.)
ТипРегистратора = Регистр.Регистраторы.Тип.ИмяТипа;
// Альтернативно, если нужно определить тип самого регистра:
ТипРегистра = ВЫРАЗИТЬ(Регистр.Тип КАК Строка); // Вернет "РегистрНакопления"
Этот подход дает максимальную гибкость, так как позволяет:
- 🔍 Получать не только тип регистратора, но и структуру регистра (измерения, ресурсы, реквизиты).
- 🔄 Динамически строить запросы в зависимости от типа регистра.
- 📋 Проверять наличие дополнительных свойств (например,
Периодическийдля регистров сведений).
Однако у этого метода есть ограничение: он работает только в конфигураторе или в коде, выполняемом на сервере (например, в серверных процедурах). В клиентском коде (например, в управляемых формах) доступ к метаданным может быть ограничен.
Как получить метаданные регистра, если его имя заранее неизвестно?
Если вам нужно динамически определить тип регистра по его ссылке (например, из параметра запроса), используйте следующий код:
ИмяРегистра = "ОстаткиТоваров"; // или получаем динамически
Попытка
Регистр = Метаданные.РегистрыНакопления[ИмяРегистра];
ТипРегистра = "РегистрНакопления";
Исключение
Попытка
Регистр = Метаданные.РегистрыСведений[ИмяРегистра];
ТипРегистра = "РегистрСведений";
Исключение
Попытка
Регистр = Метаданные.РегистрыБухгалтерии[ИмяРегистра];
ТипРегистра = "РегистрБухгалтерии";
Исключение
Сообщить("Регистр не найден: " + ИмяРегистра);
КонецПопытки;
КонецПопытки;
КонецПопытки;
Этот код последовательно проверяет наличие регистра в разных коллекциях метаданных.
Типичные ошибки и как их избежать
Даже опытные разработчики иногда допускают ошибки при работе с регистраторами. Вот наиболее распространенные из них и способы их предотвращения:
- Путаница между типом регистра и типом регистратора:
Как уже упоминалось,
ТипЗначения()возвращает тип ссылки на регистратор (например, документ), а не тип регистра (накопления/сведений). Чтобы избежать ошибок, всегда уточняйте, что именно вам нужно определить. - Игнорирование периодичности регистров сведений:
Если вы работаете с регистром сведений, не забывайте проверять его свойство
Периодический. Непериодические регистры не имеют поляПериод, и попытка использовать его в запросе приведет к ошибке. - Неправильная работа с виртуальными таблицами:
Виртуальные таблицы (например,
Остатки,Обороты) могут вести себя по-разному в зависимости от типа регистра. Например, для регистра бухгалтерии таблицаОборотыбудет содержать данные по счетам, а для регистра накопления — по ресурсам. - Отсутствие проверки на NULL:
В некоторых случаях регистратор может быть не заполнен (например, при ручной записи в регистр сведений). Всегда добавляйте условие
ГДЕ Регистратор ЕСТЬ NULLдля обработки таких случаев.
Еще одна распространенная ошибка — попытка получить тип регистратора из временной таблицы или результата запроса, где поле Регистратор уже преобразовано в строку или другой тип. В этом случае ТипЗначения() вернет не оригинальный тип, а тип текущего значения (например, "Строка"). Чтобы избежать этого, всегда работайте с исходными данными.
Уточнить, какой тип регистра используется (накопления/сведений/бухгалтерии)
Проверить, является ли регистр периодическим (для регистров сведений)
Определить тип регистратора (документ, справочник и т.д.)
Учесть особенности виртуальных таблиц для данного типа регистра
Добавить обработку случаев, когда регистратор не заполнен (NULL)
-->
Практические примеры: запросы для разных типов регистров
Разберем несколько реальных примеров запросов, где определение типа регистратора играет ключевую роль.
Пример 1: Получение остатков товаров с фильтрацией по типу документа-регистратора
Допустим, нам нужно получить остатки товаров, но только те, которые были сформированы документами "ПоступлениеТоваров", игнорируя другие виды движений (например, от "ОприходованиеТоваров").
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиТоваровОстатки.Номенклатура КАК Номенклатура,
| ОстаткиТоваровОстатки.КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(&ДатаОстатков) КАК ОстаткиТоваровОстатки
|ГДЕ
| ТИПЗНАЧЕНИЯ(ОстаткиТоваровОстатки.Регистратор) = ТИП(ДокументСсылка.ПоступлениеТоваров)";
Пример 2: Анализ движений по регистру бухгалтерии с группировкой по типам документов
В этом примере мы группируем обороты по счетам бухгалтерского учета в разрезе типов документов-регистраторов, чтобы понять, какие виды операций формируют основной оборот.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫРАЗИТЬ(ТИПЗНАЧЕНИЯ(Регистратор) КАК Строка) КАК ТипДокумента,
| Счет КАК Счет,
| СУММА(Сумма) КАК СуммаОборота
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(&НачалоПериода, &КонецПериода,) КАК Обороты
|СГРУППИРОВАТЬ ПО
| ТипДокумента,
| Счет";
Пример 3: Проверка актуальности данных в регистре сведений
Для периодического регистра сведений (например, курсов валют) важно убедиться, что мы получаем данные от последнего актуального регистратора. В этом примере мы отбираем только те записи, где регистратор является последним документом по дате.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| КурсыВалютСрезПоследних.Валюта КАК Валюта,
| КурсыВалютСрезПоследних.Курс КАК Курс,
| КурсыВалютСрезПоследних.Регистратор КАК Регистратор
|ИЗ
| РегистрСведений.КурсыВалют.СрезПоследних() КАК КурсыВалютСрезПоследних
|УПОРЯДОЧИТЬ ПО
| КурсыВалютСрезПоследних.Период УБЫВ";
Во всех этих примерах корректное определение типа регистратора позволяет:
- 🎯 Точнее фильтровать данные.
- 📈 Строить более информативные отчеты.
- ⚡ Оптимизировать производительность запросов.
При работе с регистрами бухгалтерии всегда проверяйте наличие связей с планом счетов. Запросы к таким регистрам без указания счета могут выполняться крайне долго из-за отсутствия индексов.
Особенности работы в разных версиях 1С
Платформа 1С:Предприятие постоянно развивается, и некоторые методы определения типов регистраторов могут отличаться в зависимости от версии. Рассмотрим ключевые различия:
| Версия платформы | Особенности работы с регистраторами | Рекомендации |
|---|---|---|
| 8.2 | Отсутствует виртуальная таблица v8:Метаданные. Для получения информации о типах нужно использовать объект Метаданные в коде. |
Используйте Метаданные.РегистрыНакопления[Имя].Регистраторы для анализа. |
| 8.3.6–8.3.10 | Появляется поддержка виртуальных таблиц метаданных, но синтаксис может отличаться. В некоторых случаях требуется явное приведение типов. | Для универсальности комбинируйте ТипЗначения() и запросы к v8:Метаданные. |
| 8.3.12+ | Полная поддержка виртуальных таблиц, включая v8:PlanTypes для анализа планов видов характеристик и счетов. |
Можно использовать ВЫРАЗИТЬ(Метаданные.Тип КАК Строка) без дополнительных преобразований. |
| 8.3.18+ (включая 8.3.21) | Добавлена поддержка новых типов регистров (например, РегистрРасчета). Расширены возможности работы с метаданными через запрос. |
Для регистров расчета используйте Метаданные.РегистрыРасчета[Имя]. |
Если вы разрабатываете решение, которое должно работать на разных версиях платформы, рекомендуется:
- Проверять версию платформы через
Платформа83илиВерсияПлатформы(). - Использовать универсальные методы (например,
ТипЗначения()), которые работают во всех версиях. - Для сложных сценариев реализовывать альтернативную логику с проверкой доступности тех или иных функций.
⚠️ Внимание: В версиях 8.3.20+ изменен механизм работы с виртуальными таблицами для регистров бухгалтерии. Теперь при обращении к таблице Обороты без указания счета может возвращаться ошибка. Всегда явно указывайте счет в условиях запроса.
FAQ: Частые вопросы по работе с регистраторами в 1С
Можно ли в одном запросе получить данные из регистров разных типов?
Технически да, но это требует осторожности. Вы можете использовать конструкцию ОБЪЕДИНИТЬ для объединения результатов из разных регистров, однако:
- Структура полей в итоговой выборке должна совпадать.
- Производительность такого запроса будет ниже, чем у отдельных запросов.
- Для регистров бухгалтерии и накопления могут потребоваться разные виртуальные таблицы (например,
ОстаткиvsОбороты).
Пример:
ВЫБРАТЬ
"РегистрНакопления" КАК Источник,
ОстаткиТоваров.Номенклатура КАК Номенклатура,
ОстаткиТоваров.КоличествоОстаток КАК Количество
ИЗ
РегистрНакопления.ОстаткиТоваров.Остатки(&Дата) КАК ОстаткиТоваров
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"РегистрСведений" КАК Источник,
ЦеныНоменклатуры.Номенклатура КАК Номенклатура,
ЦеныНоменклатуры.Цена КАК Количество
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних() КАК ЦеныНоменклатуры
Как определить тип регистратора, если он является справочником, а не документом?
Если регистратором выступает справочник (например, в регистре сведений "Цены номенклатуры"), то ТипЗначения() вернет значение вида СправочникСсылка.ИмяСправочника. Чтобы отличить справочник от документа, проверяйте начало строки:
Тип = ТипЗначения(Регистратор);
Если НАЧИНАЕТСЯСТР(Тип, "СправочникСсылка.") Тогда
// Это справочник
ИначеЕсли НАЧИНАЕТСЯСТР(Тип, "ДокументСсылка.") Тогда
// Это документ
КонецЕсли;
В регистрах сведений справочники-регистраторы часто используются для хранения "ручных" записей (например, установка цен вручную).
Почему запрос к регистру бухгалтерии выполняется очень долго?
Основные причины:
- Отсутствие фильтра по счету: без указания счета или диапазона счетов платформа сканирует все движения по регистру.
- Большой временной интервал: обороты за несколько лет могут содержать миллионы записей.
- Сложные соединения: связка с другими таблицами (например, с документами-регистраторами) без индексов.
- Неправильное использование виртуальных таблиц: например, запрос к
ОстаткивместоОборотыдля анализа движений.
Решения:
- Всегда указывайте счет или диапазон счетов в условии
ГДЕ. - Разбивайте большие периоды на более мелкие интервалы.
- Используйте
ИНДЕКСИРОВАТЬ ПОдля ускорения соединений.
Как получить список всех регистраторов для конкретного регистра?
Чтобы получить полный список типов документов или справочников, которые могут быть регистраторами для данного регистра, используйте следующий код:
// Получаем объект регистра
Регистр = Метаданные.РегистрыСведений.КурсыВалют;
// Перебираем все возможные типы регистраторов
Для Каждого ТипРегистратора Из Регистр.Регистраторы Цикл
Сообщить(ТипРегистратора.ИмяТипа); // Например, "ДокументСсылка.УстановкаКурсовВалют"
КонецЦикла;
Этот код выведет все типы объектов, которые могут быть регистраторами для регистра "КурсыВалют".
Можно ли изменить тип регистратора для существующего регистра?
Нет, тип регистратора определяется на этапе создания регистра в конфигураторе и не может быть изменен программно. Если вам нужно добавить новый тип регистратора (например, разрешить запись в регистр не только документу "Поступление", но и "Оприходование"), необходимо:
- Открыть регистр в конфигураторе (раздел "Объекты конфигурации").
- В свойствах регистра найти коллекцию "Регистраторы".
- Добавить новый тип объекта (документ, справочник) в список.
- Обновить конфигурацию базы данных.
Изменение списка регистраторов может потребовать перезаписи данных в регистре, если новые регистраторы имеют другую структуру.