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

· 9 мин

Содержание

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

Типичная ситуация: в регистре накопления миллион движений, а нужно отобрать только те, что сделали реализации и возвраты, или вывести колонку «Каким документом проведено». Поле Регистратор составное, в нём ссылки на десяток видов документов. Ниже — как определить тип документа средствами запроса, как отфильтровать по нескольким типам и как при этом не уронить производительность.

Как устроено составное поле со ссылками на документы

Чтобы понимать, почему одни варианты работают быстро, а другие медленно, полезно знать, как платформа хранит такие поля.

Поле с одним типом ссылки (например, реквизит Договор типа СправочникСсылка.ДоговорыКонтрагентов) хранится в базе как одна колонка с уникальным идентификатором. Тип в ней не записан: он известен заранее из метаданных.

Составное поле устроено иначе. В таблице СУБД под него заводится несколько колонок:

  • 🔹 признак вида значения (ссылка, число, строка, дата и т. д.);
  • 🔹 номер таблицы, на которую указывает ссылка, — это и есть тип документа;
  • 🔹 сам идентификатор ссылки.

Отсюда главный вывод: тип документа в составном поле уже лежит в отдельной колонке. Проверка типа через ТИПЗНАЧ или ССЫЛКА сводится к сравнению этой колонки с константой. Никаких соединений с таблицами документов для этого не нужно.

Где встречаются составные поля с документами:

ПолеГдеЧто в нём
Регистраторрегистры накопления, бухгалтерии, сведений (подчинённые регистратору)документ, который сделал движение
Ссылкажурналы документовлюбой документ из состава журнала
ДокументОснование, Основание и подобные реквизитыдокументы конфигурациидокумент-основание разных видов
Объект, Предмет в служебных регистрах сведенийверсии, файлы, задачиссылка на любой объект
Субконто1..3регистр бухгалтериииногда документы расчётов

Если поле не составное, проверять тип бессмысленно: в нём всегда один вид документа.

Функция ТИПЗНАЧ: получить тип документа в запросе

ТИПЗНАЧ возвращает тип значения поля. Его можно вывести в результат, сгруппировать по нему или сравнить с конкретным типом.

Сравнение с конкретным типом

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

Внутри ТИП() пишут имя таблицы запроса — Документ.РеализацияТоваровУслуг, а не имя типа из встроенного языка. Варианты ТИП(ДокументСсылка.РеализацияТоваровУслуг) или ТИП("ДокументСсылка...") в тексте запроса не сработают: запрос не пройдёт синтаксический контроль.

Тип как колонка результата

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

Такой запрос за секунды показывает, какие виды документов вообще двигают регистр и сколько их. Удобно, когда разбираешься в чужой доработке.

В колонке ТипДокумента придёт значение типа Тип. В отчёте оно выглядит неинформативно, поэтому имя документа получают уже в коде:

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    ОбъектМетаданных = Метаданные.НайтиПоТипу(Выборка.ТипДокумента);
    Если ОбъектМетаданных <> Неопределено Тогда
        Сообщить(ОбъектМетаданных.Синоним + ": " + Формат(Выборка.Документов, "ЧГ=0"));
    КонецЕсли;
КонецЦикла;

Метаданные.НайтиПоТипу() возвращает объект метаданных документа, у которого есть Имя и Синоним. Проверка на Неопределено защищает от неожиданных значений в составном поле.

Тип в параметре запроса

Тип можно передать снаружи. Тогда в коде создают значение типа ДокументСсылка:

Запрос.УстановитьПараметр("ТипДокумента", Тип("ДокументСсылка.РеализацияТоваровУслуг"));

А в тексте запроса пишут ТИПЗНАЧ(Движения.Регистратор) = &ТипДокумента. Частая ошибка — передать Тип("ДокументОбъект.…"): запрос выполнится без ошибок, но вернёт пустой результат, потому что в поле лежат ссылки, а не объекты.

Оператор ССЫЛКА в условиях отбора

ССЫЛКА делает то же самое, но читается проще:

ГДЕ
    Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг

Отрицание записывают через НЕ:

ГДЕ
    НЕ Движения.Регистратор ССЫЛКА Документ.КорректировкаРегистров

Где ССЫЛКА особенно удобен:

  • ✅ в ВЫБОР КОГДА … ТОГДА — чтобы вывести понятное название вида документа прямо в запросе;
  • ✅ в условиях соединения — когда к составному полю нужно присоединить таблицу только одного вида документа;
  • ✅ в условиях отбора в системе компоновки данных, куда пользователь сам добавляет поля.

Пример вычисляемой колонки с названием:

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

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

ТИПЗНАЧ или ССЫЛКА: что выбрать

ЗадачаУдобнееПочему
Отбор по одному виду документаССЫЛКАкороче, читается как фраза
Тип передаётся параметромТИПЗНАЧССЫЛКА требует имя таблицы в тексте
Группировка или вывод типаТИПЗНАЧССЫЛКА возвращает только истину или ложь
Отбор по списку типов из параметраТИПЗНАЧ … Всписок собирается в коде

По скорости разницы нет: оба варианта сравнивают колонку с номером таблицы.

Регистраторы в виртуальных таблицах регистров

С виртуальными таблицами регистров есть тонкость. Поле Регистратор доступно не во всех.

  • 📌 Остатки — регистратора нет. Остаток не привязан к документу, он сворачивается по измерениям.
  • 📌 Обороты и ОстаткиИОбороты — регистратор появляется, только если в параметре «Периодичность» указать Регистратор или Запись.
  • 📌 Физическая таблица регистра (РегистрНакопления.ТоварыНаСкладах без суффикса) — регистратор есть всегда.

Пример оборотов в разрезе документов, а затем отбор по типу:

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

Обратите внимание, где стоят условия. Отбор по складу — в параметре «Условие» виртуальной таблицы: туда можно писать условия на измерения, и платформа применит их до расчёта. Отбор по регистратору — в ГДЕ внешнего запроса. Регистратор не является измерением, поэтому в параметре условия его использовать нельзя.

Если нужен отбор по регистратору на большом периоде, сравните скорость с вариантом через физическую таблицу движений. Виртуальная таблица с периодичностью «Регистратор» сначала разворачивает обороты по всем документам и только потом отбрасывает лишние.

Регистр бухгалтерии

В регистре бухгалтерии типичная задача — найти проводки конкретного вида документа по счёту. Физическая таблица там тоже даёт поле Регистратор, и проверка через ССЫЛКА пишется точно так же. Для виртуальной таблицы ДвиженияССубконто логика та же: поле Регистратор в ней есть, а отбор по типу документа надёжнее ставить в ГДЕ внешнего запроса. Какие поля допустимы в параметре условия конкретной таблицы, показывает конструктор запроса.

Отбор по нескольким типам документов сразу

Три рабочих варианта, от простого к гибкому.

Вариант 1. Через ИЛИ

ГДЕ
    (Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
        ИЛИ Движения.Регистратор ССЫЛКА Документ.ВозвратТоваровОтПокупателя)

Не забудьте скобки, если в ГДЕ есть и другие условия через И: без них приоритет операций изменит смысл отбора.

Вариант 2. Через В со списком типов

ГДЕ
    ТИПЗНАЧ(Движения.Регистратор) В (
        ТИП(Документ.РеализацияТоваровУслуг),
        ТИП(Документ.ВозвратТоваровОтПокупателя))

Компактнее, когда видов документов пять-шесть.

Вариант 3. Список типов параметром

Подходит, когда набор документов задаёт пользователь или настройка:

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

Запрос.УстановитьПараметр("ТипыДокументов", ТипыДокументов);
ГДЕ
    ТИПЗНАЧ(Движения.Регистратор) В (&ТипыДокументов)

Если параметр — пустой массив, запрос вернёт пустой результат. Это поведение стоит учесть в коде: проверьте ТипыДокументов.Количество() до выполнения и решите, что значит «ничего не выбрано» — «все документы» или «ни одного».

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

Тип определили, теперь нужен номер, дата или контрагент документа. Тут прячется главная ловушка производительности.

Запись Движения.Регистратор.Контрагент выглядит безобидно. Но платформа не знает заранее, какой документ лежит в поле. Она строит левое соединение со всеми таблицами документов, которые могут оказаться регистратором. Если таких видов 40 — будет 40 соединений.

Правильный путь — явно привести поле к нужному типу через ВЫРАЗИТЬ:

ВЫБРАТЬ
    Движения.Регистратор,
    ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Контрагент КАК Контрагент,
    ВЫРАЗИТЬ(Движения.Регистратор КАК Документ.РеализацияТоваровУслуг).Номер КАК Номер
ИЗ
    РегистрНакопления.ТоварыНаСкладах КАК Движения
ГДЕ
    Движения.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг

Теперь соединение одно. Для строк, где регистратор другого вида, ВЫРАЗИТЬ вернёт NULL — поэтому отбор по типу в ГДЕ здесь логичен.

Ещё два приёма для того же:

  • 🔸 Стандартные реквизиты. Дата и Номер есть у любого документа. Если в конфигурации есть журнал с нужными видами документов, можно соединиться с журналом по ссылке и взять дату и номер из него — журнал хранит их в своей таблице.
  • 🔸 Временная таблица. Сначала отберите ссылки нужного типа в ПОМЕСТИТЬ, затем соединитесь с таблицей документа по ссылке. На больших объёмах это часто быстрее одного «толстого» запроса.
Проверьте себя
Что вернёт ВЫРАЗИТЬ(Регистратор КАК Документ.РеализацияТоваровУслуг), если регистратор — поступление?
Какое значение передать в параметр &ТипДокумента для сравнения с ТИПЗНАЧ(Регистратор)?
Есть ли поле Регистратор в виртуальной таблице Остатки?

Почему запрос не отбирает документы: частые ошибки

Диагностика: выберите симптом

Ещё одна ошибка, которую не ловит синтаксический контроль: имя документа написано с опечаткой в условии внутри строки, собранной кодом. Платформа сообщит, что таблица не найдена, только при выполнении. Собирайте текст через конструктор запроса или проверяйте имя через Метаданные.Документы.Найти("Имя") до выполнения.

Производительность: что ускоряет запрос с отбором по типу

Сама проверка типа дешёвая. Медленным запрос делают соседние конструкции.

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

Если отбор по виду документа нужен постоянно (например, в отчёте, который открывают каждый день), подумайте о журнале документов или об отдельном регистре сведений, где тип записан явно. Это решение уровня доработки конфигурации — его согласовывают с тем, кто сопровождает базу.

Частые вопросы

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