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