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