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