Язык запросов 1С

Тип документа в запросе 1С 8.3: оператор ССЫЛКА, ТИПЗНАЧЕНИЯ и ВЫРАЗИТЬ

Коротко

Проверить тип документа или составного реквизита в запросе 1С 8.3 можно двумя способами: логическим оператором Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг или сравнением типа ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(Документ.РеализацияТоваровУслуг). Для отбора сразу по нескольким видам документов компактнее использовать список типов: ТИПЗНАЧЕНИЯ(Регистратор) В (ТИП(Документ.РеализацияТоваровУслуг), ТИП(Документ.АвансовыйОтчет)).

Никогда не обращайтесь к реквизитам составного поля напрямую через точку (Регистратор.Контрагент) — СУБД построит LEFT JOIN ко всем таблицам документов, входящим в составной тип. Всегда сужайте тип оператором ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент, а для вывода названия вида документа текстом используйте ПРЕДСТАВЛЕНИЕ(ТИПЗНАЧЕНИЯ(Регистратор)).

Почему поле Регистратор и составные ссылки требуют особого подхода

В типовых конфигурациях 1С:Предприятие 8.3 (ERP, КА, УТ 11, БП 3.0, ЗУП 3.1) измерение или стандартное поле Регистратор в регистрах накопления, бухгалтерии и подчинённых регистрах сведений всегда имеет составной тип данных (ЛюбаяСсылка или перечень из 20–80 видов документов, которые формируют движения по этому регистру). Аналогично устроены реквизиты вроде ДокументОснование, ОбъектРасчетов или субконто на счетах учёта (Субконто1, Субконто2).

На уровне базы данных платформа 1С хранит составную ссылку регистратора в двух физических полях SQL-таблицы (а для произвольных составных реквизитов — дополнительно с полем вида типа):

  • _RecorderTRef (Type Reference, binary(4)) — номер таблицы метаданных (конкретного вида документа);
  • _RecorderRRef (Row Reference, binary(16)) — уникальный идентификатор (UUID) конкретной строки в таблице этого документа;
  • у обычных реквизитов и измерений составного типа (_FldXXX) при смешении ссылок разных видов или примитивов также создаётся однобайтовый префикс вида типа _TYPE (binary(1), где 0x08 означает ссылку).

Поскольку в одной колонке лежат ссылки на разные таблицы базы данных, в языке запросов 1С предусмотрены специальные конструкции для работы с кодом типа TRef: оператор проверки ссылки ССЫЛКА, пара функций ТИПЗНАЧЕНИЯ() / ТИП() и оператор приведения типа ВЫРАЗИТЬ().

Оператор ССЫЛКА в запросе 1С: проверка одного вида документа

Логический оператор ССЫЛКА в запросе 1С проверяет, принадлежит ли значение поля или выражения указанному типу метаданных (конкретному документу, справочнику, плану видов характеристик) либо всем объектам вида (например, Документ или Справочник). Результатом вычисления всегда является значение типа Булево (ИСТИНА или ЛОЖЬ).

Оператор можно использовать как в секции отбора ГДЕ, так и внутри условной конструкции ВЫБОР КОГДА ... ТОГДА ... КОНЕЦ в списке полей выборки.

ВЫБРАТЬ
    ТоварыНаСкладах.Период КАК Период,
    ТоварыНаСкладах.Регистратор КАК Регистратор,
    ТоварыНаСкладах.Номенклатура КАК Номенклатура,
    ТоварыНаСкладах.Количество КАК Количество,
    ВЫБОР
        КОГДА ТоварыНаСкладах.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
            ТОГДА "Отгрузка клиенту"
        КОГДА ТоварыНаСкладах.Регистратор ССЫЛКА Документ.ТребованиеНакладная
            ТОГДА "Списание в производство"
        ИНАЧЕ "Прочее движение"
    КОНЕЦ КАК ВидОперации
ИЗ
    РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ГДЕ
    ТоварыНаСкладах.Период МЕЖДУ &НачалоПериода И &КонецПериода
    И (ТоварыНаСкладах.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
        ИЛИ ТоварыНаСкладах.Регистратор ССЫЛКА Документ.ТребованиеНакладная)
<Выражение> ССЫЛКА <ИмяТипа>
Выражениепроверяемое поле запроса (например, Регистратор)
ИмяТипатаблица метаданных (Документ.РеализацияТоваровУслуг) или вид (Документ, Справочник)
НЕ <Выражение> ССЫЛКА ...отрицание ставится строго перед левым операндом
→ Булево (сравнение _TRef в SQL без JOIN)

Обратите внимание на синтаксис отрицания: в языке запросов 1С нельзя написать Регистратор НЕ ССЫЛКА Документ.АвансовыйОтчет — конструктор запроса выдаст синтаксическую ошибку. Ключевое слово НЕ всегда ставится перед проверяемым полем: НЕ Регистратор ССЫЛКА Документ.АвансовыйОтчет.

Отбор по типу документа в запросе 1С через ТИПЗНАЧЕНИЯ и ТИП

Второй способ определить вид документа — функция ТИПЗНАЧЕНИЯ в запросе 1С 8.3 в паре с литеральной функцией ТИП(<ИмяТипа>). Первая возвращает тип значения, хранящегося в поле текущей строки выборки, а вторая формирует константу типа по его имени в метаданных.

Главное практическое преимущество ТИПЗНАЧЕНИЯ() перед оператором ССЫЛКА проявляется тогда, когда нужно отобрать движения сразу по нескольким видам документов или передать тип документа из кода 1С через параметр запроса.

ВЫБРАТЬ
    Взаиморасчеты.Период КАК Период,
    Взаиморасчеты.Регистратор КАК ДокументДвижения,
    Взаиморасчеты.Контрагент КАК Контрагент,
    Взаиморасчеты.СуммаВзаиморасчетов КАК Сумма
ИЗ
    РегистрНакопления.РасчетыСПоставщиками КАК Взаиморасчеты
ГДЕ
    Взаиморасчеты.Период МЕЖДУ &НачалоПериода И &КонецПериода
    И ТИПЗНАЧЕНИЯ(Взаиморасчеты.Регистратор) В (
        ТИП(Документ.ПоступлениеТоваровУслуг),
        ТИП(Документ.АвансовыйОтчет),
        ТИП(Документ.СписаниеСРасчетногоСчета)
    )
ТИПЗНАЧЕНИЯ(Поле) / ТИП(ИмяТипа)
ТИПЗНАЧЕНИЯ(Выражение)возвращает тип значения поля в запросе (аналог ТипЗнч())
ТИП(ИмяТипа)литерал типа для конкретной таблицы (Документ.АвансовыйОтчет) или примитива
&МассивТиповсписок значений Тип("ДокументСсылка.Имя") для оператора В (...)
→ Тип (для сравнения через = и В (...))

Как передавать параметр типа из встроенного языка 1С, если список видов документов формируется динамически на сервере:

МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("ДокументСсылка.ПоступлениеТоваровУслуг"));
МассивТипов.Добавить(Тип("ДокументСсылка.АвансовыйОтчет"));

Запрос.УстановитьПараметр("МассивТипов", МассивТипов);
В типовых ERP и КА у одного регистра накопления бывает более 40 видов регистраторов. Чтобы не искать их имена в дереве метаданных Конфигуратора вручную, откройте ИИ Консоль запросов 1С: агент видит структуру вашей базы, сам подберёт нужные виды документов регистратора и проверит запрос на живых данных.

Разница между ССЫЛКА, ТИПЗНАЧЕНИЯ и ВЫРАЗИТЬ

У разработчиков часто возникает вопрос, что работает быстрее на больших регистрах — ССЫЛКА или ТИПЗНАЧЕНИЯ(...) = ТИП(...). Для проверки одного конкретного вида документа оба варианта транслируются платформой 1С в идентичное условие SQL по полю _TRef. Разница заключается в читаемости текста запроса, работе со списками В (...) и проверке обобщённых видов метаданных.

Конструкция языка запросов Что возвращает Где применяется Особенности и влияние на SQL-запрос
Поле ССЫЛКА Документ.Имя Булево Условия ГДЕ, ПО (в соединениях), ветки ВЫБОР КОГДА Поддерживает обобщённый вид Поле ССЫЛКА Документ (любой документ). Нельзя передать список типов через В (...) и нельзя передать тип параметром.
ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.Имя) Булево (сама функция возвращает Тип) Условия ГДЕ, оператор В (...), поля выборки и СГРУППИРОВАТЬ ПО Позволяет проверять вхождение в список В (ТИП(...), ТИП(...)), передавать &ПараметрТипа и группировать выборку по видам документов. Не поддерживает обобщённый ТИП(Документ).
ВЫРАЗИТЬ(Поле КАК Документ.Имя) Типизированная ссылка или NULL Поля ВЫБРАТЬ, разыменование через точку, условия ПО и ГДЕ Приводит составной тип к одному конкретному типу. Если в строке лежит другой вид документа, возвращает NULL. Ограничивает LEFT JOIN в SQL ровно одной таблицей.

Как вывести вид документа в запросе 1С отдельной колонкой

Если в отчёте СКД или таблице результата запроса нужно получить отдельную текстовую колонку с человекочитаемым названием вида документа (например, «Реализация товаров и услуг» или «Поступление на расчетный счет»), а также сгруппировать обороты по типам регистраторов, используйте связку функций ПРЕДСТАВЛЕНИЕ(ТИПЗНАЧЕНИЯ(Поле)).

Сама функция ТИПЗНАЧЕНИЯ(Регистратор) возвращает системное значение типа Тип — по нему удобно группировать и сортировать строки на стороне сервера БД, а функция ПРЕДСТАВЛЕНИЕ() возвращает пользовательское представление типа (синоним объекта метаданных).

ВЫБРАТЬ
    ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор) КАК ТипРегистратора,
    ПРЕДСТАВЛЕНИЕ(ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор)) КАК ВидДокументаТекст,
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Хозрасчетный.Регистратор) КАК КоличествоДокументов,
    СУММА(Хозрасчетный.Сумма) КАК ОбщаяСуммаПроводок
ИЗ
    РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(
        &НачалоПериода,
        &КонецПериода,
        Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.РасчетыСПокупателямиИЗаказчиками)
    ) КАК Хозрасчетный
СГРУППИРОВАТЬ ПО
    ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор)

Обратите внимание: в секцию СГРУППИРОВАТЬ ПО достаточно включить только ТИПЗНАЧЕНИЯ(Хозрасчетный.Регистратор). Оборачивать функцию ПРЕДСТАВЛЕНИЕ() в агрегатную функцию не нужно — платформа 1С вычисляет строковое представление уже при формировании результата по сгруппированному типу.

Оператор ВЫРАЗИТЬ: как не положить СУБД на составном типе

Самая тяжёлая ошибка производительности при работе с регистрами 1С возникает в тот момент, когда разработчик обращается к реквизиту составного поля напрямую через точку: например, пишет Регистратор.Номер, Регистратор.Дата, Регистратор.Организация или Регистратор.Контрагент.

Почему это опасно? Регистратор не является одной таблицей в СУБД. Чтобы достать реквизит Номер или Контрагент для неизвестного заранее типа ссылки, транслятор запросов 1С вынужден добавить в SQL-запрос левое соединение (LEFT OUTER JOIN) со всеми таблицами документов, которые могут быть регистраторами этого регистра и имеют одноимённый реквизит. В ERP или БП 3.0 для регистра бухгалтерии Хозрасчетный обращение Регистратор.Номер порождает соединение более чем с 80 таблицами документов, а в списке выборки появляется гигантский CASE WHEN ... THEN ... END на десятки веток. В MS SQL Server и PostgreSQL оптимизатор запросов на таком плане легко уходит в многоминутное выполнение или превышает лимит таблиц.

Даже если в секции ГДЕ вы написали отбор Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг, само по себе это условие не меняет составной тип поля Регистратор в секции ВЫБРАТЬ! Чтобы платформа соединила регистр строго с одной таблицей документа, необходимо явно сузить тип оператором ВЫРАЗИТЬ(<Поле> КАК <ИмяТипа>).

ВЫБРАТЬ
    ТоварыНаСкладах.ПериодСекунда КАК Период,
    ТоварыНаСкладах.Регистратор КАК Регистратор,
    ВЫРАЗИТЬ(ТоварыНаСкладах.Регистратор КАК Документ.РеализацияТоваровУслуг).Номер КАК НомерДокумента,
    ВЫРАЗИТЬ(ТоварыНаСкладах.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Покупатель,
    ВЫРАЗИТЬ(ТоварыНаСкладах.Регистратор КАК Документ.РеализацияТоваровУслуг).ДоговорКонтрагента КАК Договор,
    ТоварыНаСкладах.Номенклатура КАК Номенклатура,
    ТоварыНаСкладах.КоличествоРасход КАК Количество
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Обороты(
        &НачалоПериода,
        &КонецПериода,
        Регистратор,
        Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
    ) КАК ТоварыНаСкладах
ВЫРАЗИТЬ(Поле КАК Тип).Реквизит
Полереквизит или измерение составного типа (например, Регистратор)
КАК Типконкретная таблица из состава типа (Документ.РеализацияТоваровУслуг)
ЕСТЬNULL(ВЫРАЗИТЬ(...), ...)получение одноимённого реквизита из 2–3 видов документов
→ Значение реквизита или NULL (ровно 1 LEFT JOIN в SQL)

Если в одну колонку отчёта нужно вывести контрагента из двух конкретных видов документов (например, из «Реализации товаров и услуг» и «Возврата товаров от покупателя»), оберните два выражения ВЫРАЗИТЬ в функцию ЕСТЬNULL или конструкцию ВЫБОР КОГДА. Тогда SQL-запрос сделает LEFT JOIN только к этим двум таблицам документов, а не ко всем пятидесяти.

Оценить реальное время выполнения запроса и избавиться от неявных соединений по составным полям в рабочей базе проще всего через ИИ Консоль запросов 1С: покажите агенту медленный запрос, и он перепишет обращения к реквизитам регистратора через ВЫРАЗИТЬ с проверкой результата.

Частые ошибки при работе с типом документа и ССЫЛКА в запросе

  • Разыменование составного поля без ВЫРАЗИТЬ после отбора в ГДЕ. Многие считают, что условие ГДЕ Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг автоматически подскажет платформе тип поля в списке ВЫБРАТЬ Регистратор.Контрагент. Это не так: тип колонки Регистратор остаётся составным, и 1С всё равно строит LEFT JOIN ко всем таблицам документов, где есть реквизит Контрагент. Всегда пишите ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент.
  • Неверный порядок слов в отрицании НЕ ССЫЛКА. Запись ГДЕ Регистратор НЕ ССЫЛКА Документ.ОприходованиеТоваров вызывает синтаксическую ошибку Ожидается выражение. Правильный синтаксис — логическое отрицание перед всем условием: ГДЕ НЕ Регистратор ССЫЛКА Документ.ОприходованиеТоваров.
  • Передача строки вместо объекта Тип в параметр запроса. Если в запросе написано ТИПЗНАЧЕНИЯ(Регистратор) = &ТипДок, а в коде вы передали строку Запрос.УстановитьПараметр("ТипДок", "Документ.РеализацияТоваровУслуг"), условие вернёт ЛОЖЬ для всех строк. Передавать нужно именно объект типа: Тип("ДокументСсылка.РеализацияТоваровУслуг").
  • Попытка использовать ВЫРАЗИТЬ к типу, не входящему в составной тип поля. Если вы попытаетесь выполнить ВЫРАЗИТЬ(Поле КАК Документ.ЗаказКлиента) для реквизита, в описании типов которого в Конфигураторе нет документа «Заказ клиента», платформа выбросит ошибку выполнения запроса Тип не может быть выбран в запросе или Неверные параметры "ВЫРАЗИТЬ".
  • Сравнение результата ВЫРАЗИТЬ с пустой ссылкой вместо ЕСТЬ NULL. Если значение поля не относится к указанному в ВЫРАЗИТЬ типу, результатом приведения будет NULL, а не ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг.ПустаяСсылка). Проверять несовпадение типа у приведённого поля нужно через ЕСТЬ NULL или функцию ЕСТЬNULL().
  • Использование ТИП(Документ) по аналогии с ССЫЛКА Документ. Оператор Поле ССЫЛКА Документ корректен и проверяет, является ли ссылка любым документом конфигурации. А вот конструкция ТИП(Документ) в функции ТИП() недопустима — в ТИП() всегда указывается конкретный вид объекта метаданных (например, ТИП(Документ.АвансовыйОтчет)).

Частые вопросы о типе документа в запросе 1С

Что быстрее в запросе 1С 8.3: оператор ССЫЛКА или ТИПЗНАЧЕНИЯ?

При отборе по одному виду документа скорости выполнения полностью одинаковы: и оператор Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг, и условие ТИПЗНАЧЕНИЯ(Регистратор) = ТИП(Документ.РеализацияТоваровУслуг) транслируются платформой 1С в одно и то же сравнение четырехбайтового поля типа _TRef в SQL без соединений с таблицей документа. Выбирайте ССЫЛКА для одиночных проверок и проверки обобщённого вида Документ, а ТИПЗНАЧЕНИЯ() В (...) — когда нужно компактно отобрать сразу несколько видов документов или передать массив типов через параметр.

Как в запросе 1С 8.3 вывести вид документа строкой?

Используйте в списке полей выборки комбинацию функций ПРЕДСТАВЛЕНИЕ(ТИПЗНАЧЕНИЯ(Регистратор)) КАК ВидДокумента. Функция ТИПЗНАЧЕНИЯ возвращает системный тип ссылки из текущей записи, а функция ПРЕДСТАВЛЕНИЕ преобразует его в пользовательское наименование объекта метаданных (синоним документа, например «Реализация товаров и услуг»). Если в СКД поле выводится напрямую в группировку, достаточно выбрать ТИПЗНАЧЕНИЯ(Регистратор) — система компоновки данных сама сформирует текстовое представление типа в отчёте.

Зачем нужен оператор ВЫРАЗИТЬ, если в ГДЕ уже стоит отбор через ССЫЛКА?

Условие Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг в секции ГДЕ фильтрует строки выборки, но не меняет составной тип самого поля Регистратор для транслятора запросов. Если в секции ВЫБРАТЬ обратиться к реквизиту через точку напрямую (Регистратор.Контрагент), платформа 1С добавит в SQL-запрос LEFT JOIN ко всем таблицам документов регистра, у которых есть реквизит Контрагент. Оператор ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент явно приводит поле к одному типу, благодаря чему СУБД выполняет соединение строго с одной таблицей документа.