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

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

При работе с запросами в платформе «1С:Предприятие 8» разработчики часто сталкиваются с необходимостью связать несколько таблиц с помощью левого соединения (ЛЕВОЕ СОЕДИНЕНИЕ) и проверить, заполнены ли данные в присоединенной таблице. Особую сложность вызывают поля со строками неограниченной длины (например, адреса, ссылки на внешние ресурсы или комментарии). Если просто попытаться сравнить такое поле с пустой строкой в секции ВЫБОР, СУБД вернет ошибку или запрос отработает некорректно.

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

Выясняем причину: почему простой запрос не работает?

Давайте проанализируем ситуацию, с которой столкнулась автор темы. Нам необходимо связать документ с таблицей присоединенных файлов Google Drive и определить, прикреплен ли файл к документу. Поле СсылкаНаФайл имеет тип «Строка неограниченной длины».

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


ВЫБОР
    КОГДА (ВЫРАЗИТЬ(Кос_ФайлыGDrive.СсылкаНаФайл КАК СТРОКА(1000))) = ""
        ТОГДА 0
    КОГДА (ВЫРАЗИТЬ(Кос_ФайлыGDrive.СсылкаНаФайл КАК СТРОКА(1000))) <> ""
        ТОГДА 1
    ИНАЧЕ 0
КОНЕЦ КАК Кос_GDrive

Этот код содержит критическую логическую ошибку, из-за которой запрос работает не так, как ожидалось. Дело в механизме работы операции ЛЕВОЕ СОЕДИНЕНИЕ. Если для документа в присоединенной таблице файлов не будет найдено соответствие, то СУБД во всех полях присоединенной таблицы вернет значение NULL.

Когда СУБД пытается выполнить конструкцию ВЫРАЗИТЬ(NULL КАК СТРОКА(1000)), результатом также становится значение NULL. В языке SQL любое сравнение значения NULL с чем-либо (даже проверка вида NULL = "" или NULL <> "") всегда возвращает ложь (точнее, логическое значение UNKNOWN). В результате выполнение запроса всегда уходит в ветку ИНАЧЕ 0, из-за чего система считает, что файла нет, даже если запись просто отсутствовала в соединении.

Решение №1: Исправление исходного кода через ЕСТЬNULL и ВЫРАЗИТЬ

Чтобы заставить эту логику работать, нам нужно явно обработать значение NULL, заменив его на пустую строку до выполнения сравнения. Для этого используется функция ЕСТЬNULL (в англоязычном варианте — ISNULL).

Разберем по шагам правильное построение этой функции:

  1. Сначала мы оборачиваем поле в функцию ЕСТЬNULL(Кос_ФайлыGDrive.СсылкаНаФайл, ""). Если поле содержит NULL, СУБД подставит вместо него пустую строку.
  2. Поскольку исходный тип поля — строка неограниченной длины, СУБД не может напрямую сравнивать его со значением "" в блоке КОГДА. Нам обязательно нужно использовать оператор приведения типов ВЫРАЗИТЬ.
  3. Для проверки заполненности нам совершенно не нужно приводить строку к длине 1000 символов. Достаточно ограничить её всего одним символом! Это существенно снизит нагрузку на оперативную память сервера СУБД.

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


ВЫБОР
    КОГДА ВЫРАЗИТЬ(ЕСТЬNULL(Кос_ФайлыGDrive.СсылкаНаФайл, "") КАК СТРОКА(1)) = ""
        ТОГДА 0
    ИНАЧЕ 1
КОНЕЦ КАК Кос_GDrive

Этот вариант полностью работоспособен. Сначала функция ЕСТЬNULL вернет либо реальную строку ссылки, либо пустую строку. Затем оператор ВЫРАЗИТЬ(... КАК СТРОКА(1)) усечет результат до 1 символа, превратив неограниченную строку в строку ограниченной длины. После этого сравнение с "" отработает корректно на уровне СУБД.

Решение №2: Оптимальный способ (Проверка по ссылке)

Хотя первое решение является рабочим, с точки зрения стандартов разработки и оптимизации запросов 1С оно далеко не самое лучшее. В сообщении форума автор пишет важную фразу: «Мне нужно — есть он или нет, сама ссылка не нужна».

Если нам нужно только проверить сам факт физического наличия записи в присоединенной таблице, то нам вообще не требуется обращаться к тяжелым текстовым полям неограниченной длины! Считывание полей неограниченной длины (блоков данных типа BLOB в СУБД) — это крайне ресурсоемкая операция.

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

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


ВЫБОР
    КОГДА Кос_ФайлыGDrive.Ссылка ЕСТЬ NULL
        ТОГДА 0
    ИНАЧЕ 1
КОНЕЦ КАК Кос_GDrive

Почему этот вариант гораздо лучше:

Решение №3: Возврат логического типа (Булево)

В профессиональной разработке на платформе 1С принято возвращать логический тип (ИСТИНА или ЛОЖЬ), если поле отвечает на вопрос «Да/Нет» или «Есть/Нет». Использование чисел 1 и 0 усложняет дальнейшую работу с результатом запроса в коде конфигурации.

Давайте перепишем наш оптимизированный запрос с использованием правильного типа данных:


ВЫБОР
    КОГДА Кос_ФайлыGDrive.Ссылка ЕСТЬ NULL
        ТОГДА ЛОЖЬ
    ИНАЧЕ ИСТИНА
КОНЕЦ КАК Кос_GDrive

Теперь при обходе результата запроса во встроенном языке 1С вы сможете писать красивый, лаконичный код без лишних сравнений:


Пока Выборка.Следующий() Цикл
    Если Выборка.Кос_GDrive Тогда
        // Файл прикреплен, выполняем логику
    КонецЕсли;
КонецЦикла;

Важные технические ограничения функции ВЫРАЗИТЬ

Если в других задачах вам все же потребуется преобразовывать строки неограниченной длины к ограниченному типу для вывода в отчеты или дальнейшей обработки, помните о важных правилах платформы 1С:

← На главную