Как в запросе 1С проверить тип значения: справочник это или документ?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с полями составного типа данных (например, такими как Субконто, Владелец, Регистратор или любые произвольные дополнительные реквизиты) перед разработчиком часто возникает задача: определить, к какому именно классу метаданных относится текущее значение. Нам может потребоваться выяснить, является ли объект справочником или документом, не прибегая к жесткому перечислению десятков и сотен конкретных таблиц вручную.

В рамках этой статьи мы подробно разберем, почему простые интуитивные решения (так называемые «костыли») могут быть опасны для производительности вашей базы данных, и рассмотрим три надежных профессиональных метода решения этой задачи в платформе «1С:Предприятие 8».

Почему популярные «быстрые» способы — это антипаттерны?

Среди разработчиков, особенно начинающих, популярна идея проверять тип объекта по наличию у него уникальных системных реквизитов. Например, если у объекта есть реквизит Проведен — значит, это документ. Если есть реквизит Код — значит, это справочник. В запросе это пытаются реализовать через проверку на NULL при неявном соединении.

Давайте проанализируем, почему этот подход категорически не рекомендуется использовать в реальных задачах:

  1. Проблема производительности (Неявные соединения - Implicit Joins): Когда мы пишем в запросе конструкцию вида РеквизитСоставногоТипа.Проведен, платформа 1С на уровне СУБД генерирует левое соединение (LEFT JOIN) со всеми таблицами, которые входят в этот составной тип. Если тип данных включает 50 документов, СУБД выполнит 50 соединений! Это приведет к колоссальному падению скорости выполнения запроса и избыточной нагрузке на сервер.
  2. Ложные срабатывания: Не все документы имеют свойство проведения (например, непроводимые документы типа «Встреча» или «Электронное письмо»). Для них проверка на Проведен вернет ложное значение. С другой стороны, справочники могут не иметь кода (длина кода установлена в 0), а документы, наоборот, могут содержать реквизит Код или другие схожие по наименованию поля.
  3. Планы характеристик и другие объекты: Помимо справочников и документов, в системе существуют планы видов характеристик, планы счетов, бизнес-процессы и задачи. Попытка разделить объекты «в лоб» по реквизитам приведет к логическим ошибкам при появлении в базе новых типов данных.

Перейдем к правильным, протестированным и безопасным методам решения этой задачи.

Способ 1. Использование массива типов в параметрах запроса (Оптимальный)

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

Рассмотрим пример реализации на встроенном языке 1С:


// 1. Формируем массивы типов для документов и справочников
МассивТиповДокументов = Документы.ТипВсеСсылки().Типы();
МассивТиповСправочников = Справочники.ТипВсеСсылки().Типы();

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

Запрос.УстановитьПараметр("ТипыДокументов", МассивТиповДокументов);
Запрос.УстановитьПараметр("ТипыСправочников", МассивТиповСправочников);

РезультатЗапроса = Запрос.Выполнить();

Преимущества метода: Работает быстро, не создает лишних тяжелых соединений на уровне СУБД, код легко читать и поддерживать.

Способ 2. Динамическое формирование текста запроса

Если нам необходимо жестко зафиксировать проверку типов внутри самого SQL-запроса без использования динамических параметров-массивов, мы можем сгенерировать текст конструкции ВЫБОР КОГДА ... ССЫЛКА ... программно перед выполнением запроса.

Давайте посмотрим на пример реализации такого генератора текста:


// Инициализируем массив для накопления условий
УсловияЗапроса = Новый Массив;

// Пробегаем по метаданным всех документов конфигурации
Для Каждого МетаДокумент Из Метаданные.Документы Цикл
    УсловияЗапроса.Добавить("КОГДА Источник.СсылкаСоставногоТипа ССЫЛКА Документ." + МетаДокумент.Имя + " ТОГДА ИСТИНА");
КонецЦикла;

// Объединяем полученные строки в единый блок условий
СтрокаУсловий = СтрСоединить(УсловияЗапроса, Символы.ПС);

// Формируем итоговый текст запроса
ТекстЗапроса = 
    "ВЫБРАТЬ
    |	Источник.СсылкаСоставногоТипа КАК Объект,
    |	ВЫБОР
    |		" + СтрокаУсловий + "
    |		ИНАЧЕ ЛОЖЬ
    |	КОНЕЦ КАК ЭтоДокумент
    |ИЗ
    |	Справочник.ДоговорыКонтрагентов КАК Источник";

Запрос = Новый Запрос(ТекстЗапроса);
Выборка = Запрос.Выполнить().Выбрать();

Преимущества метода: Полученный запрос является абсолютно «чистым» для СУБД, так как оператор ССЫЛКА транслируется платформой в максимально эффективные и быстрые проверки внутренних идентификаторов таблиц.

Способ 3. Использование справочника БСП «Идентификаторы объектов метаданных» (Полностью в запросе)

Если вы разрабатываете отчет в Системе компоновки данных (СКД) или пишете сложный пакетный запрос, где крайне нежелательно использовать программную установку параметров или динамическую сборку текста, можно использовать возможности Библиотеки стандартных подсистем (БСП).

В современных конфигурациях 1С присутствует системный справочник ИдентификаторыОбъектовМетаданных. Он хранит структуру всех объектов метаданных вашей базы в виде иерархического дерева. Мы можем использовать левое соединение с этим справочником по типу пустой ссылки.

Проанализируем пример такого запроса:


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

Важное примечание: Справочник ИдентификаторыОбъектовМетаданных должен быть заполнен актуальными данными. Обычно обновление этого справочника происходит автоматически при обновлении версии конфигурации или при первом запуске предприятия.

Преимущества метода: Запрос выполняется на 100% на стороне СУБД, не требует написания кода на встроенном языке, идеально подходит для сложных аналитических отчетов и схем компоновки данных (СКД).

Резюме и рекомендации

Для выбора оптимального решения вашей задачи воспользуйтесь следующими рекомендациями:

  1. Если вы пишете стандартный алгоритм во встроенном языке и можете передать параметры — используйте Способ №1 с передачей массива ТипВсеСсылки().Типы(). Это самый простой и лаконичный код.
  2. Если вам важно получить максимальное быстродействие в высоконагруженных участках системы (например, в подписках на события или при проведении документов) — используйте динамическое конструирование условий ССЫЛКА из Способа №2.
  3. Если задача решается средствами СКД без возможности программного вмешательства — используйте связь со справочником БСП из Способа №3.
← На главную