При написании запросов в платформе «1С:Предприятие» разработчики часто сталкиваются со следующей ошибкой: «Нельзя сравнивать поля неограниченной длины». Данная ошибка возникает при попытке выполнить операцию сравнения (например, через операторы =, <>) для строковых реквизитов, длина которых в конфигураторе задана как «Неограниченная» (в базах данных MS SQL они хранятся в виде типов NTEXT или NVARCHAR(MAX), а в PostgreSQL — TEXT).
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем популярные ошибки разработчиков при работе с такими полями, найдем самые производительные способы проверки на пустоту и NULL, а также рассмотрим другие важные ограничения СУБД при работе с большими текстовыми полями.
Давайте проанализируем исходный код, с которым столкнулся автор темы на форуме:
ВЫБОР
КОГДА ПолеНеограниченнойДлинны = Null ТОГДА "1"
ИНАЧЕ код
КОНЕЦ
В этой конструкции кроются сразу две серьезные ошибки:
NULL через знак равенства (= NULL). В языке SQL и в языке запросов 1С любое сравнение значения с NULL с использованием оператора равенства всегда возвращает результат «Ложь» (или, точнее, «Неизвестно»). Конструкция Поле = NULL никогда не сработает так, как ожидает разработчик, даже если само поле имеет ограниченную длину.Выясним, как правильно решить обе эти проблемы и написать оптимальный, быстродействующий код.
Часто в запросах (особенно после левого соединения таблиц) нам необходимо проверить, не является ли поле пустым (содержит NULL). В финальном решении на форуме участники пришли к следующему коду:
ВЫБОР
КОГДА (ВЫРАЗИТЬ(ВТ_АдресТТСнежка.АдресТТСнежка КАК СТРОКА(1000))) ЕСТЬ NULL ТОГДА "НЕ УРА"
ИНАЧЕ "ура"
КОНЕЦ
Давайте проанализируем эту конструкцию. Использование оператора ВЫРАЗИТЬ здесь является абсолютно избыточным и снижает производительность СУБД.
Дело в том, что оператор ЕСТЬ NULL проверяет не внутреннее содержимое строки, а сам факт отсутствия записи в таблице. СУБД без проблем определяет отсутствие данных для любого типа реквизитов, включая неограниченные строки, без какого-либо приведения типов. Конструкция ВЫРАЗИТЬ(... КАК СТРОКА(1000)) заставляет СУБД выделять дополнительную память под буфер строки и выполнять операцию преобразования типов перед проверкой, что совершенно бессмысленно.
Как правильно и производительно проверять на NULL:
ВЫБОР
КОГДА ВТ_АдресТТСнежка.АдресТТСнежка ЕСТЬ NULL ТОГДА "НЕ УРА"
ИНАЧЕ "ура"
КОНЕЦ
Этот вариант работает значительно быстрее, так как не нагружает сервер СУБД лишними операциями приведения типов.
Если нам необходимо проверить, заполнено ли текстовое поле неограниченной длины (то есть строка не пустая и не равна ""), у нас есть несколько вариантов. Разберем их по шагам.
Вариант А. Использование функции ВЫРАЗИТЬ (Классический подход)
Для того чтобы СУБД могла сравнить строку, мы должны принудительно ограничить ее длину. Для этого используется оператор ВЫРАЗИТЬ:
ВЫБОР
КОГДА ВЫРАЗИТЬ(ВТ_АдресТТСнежка.АдресТТСнежка КАК СТРОКА(1000)) = "" ТОГДА "Пусто"
ИНАЧЕ "Заполнено"
КОНЕЦ
Этот способ рабочий, но у него есть минус: если таблица содержит тысячи строк, СУБД придется для каждой строки обрезать длинный текст до 1000 символов, что создает вычислительную нагрузку на дисковую подсистему и процессор сервера.
Вариант Б. Использование функции ПОДСТРОКА (Рекомендуемый и самый быстрый способ)
Вместо того чтобы приводить к строке ограниченной длины весь текст (например, 1000 символов), мы можем проверить только самый первый символ строки. Если первый символ является пустым, то и вся строка гарантированно пустая.
ВЫБОР
КОГДА ПОДСТРОКА(ВТ_АдресТТСнежка.АдресТТСнежка, 1, 1) = "" ТОГДА "Пусто"
ИНАЧЕ "Заполнено"
КОНЕЦ
Этот способ работает в разы быстрее на больших базах данных. СУБД считывает минимальное количество информации (всего один символ) и мгновенно выполняет сравнение.
Вариант В. Использование оператора ПОДОБНО
Оператор ПОДОБНО в языке запросов 1С изначально умеет работать с полями неограниченной длины без предварительного использования функции ВЫРАЗИТЬ. Мы можем использовать его для проверки на пустоту:
ВЫБОР
КОГДА ВТ_АдресТТСнежка.АдресТТСнежка ПОДОБНО "" ТОГДА "Пусто"
ИНАЧЕ "Заполнено"
КОНЕЦ
Этот вариант лаконичен, легко читается и не вызывает ошибок сравнения типов на уровне СУБД.
Проверка на равенство и NULL — это далеко не единственные сложности, с которыми сталкиваются программисты 1С при работе со строками неограниченной длины (такими как реквизиты «Комментарий», «Адрес», «Описание»). Рассмотрим полный список ограничений платформы и СУБД, о которых важно помнить при написании запросов:
СГРУППИРОВАТЬ ПО): СУБД не может группировать данные по полям неограниченного размера. Если вам необходимо сгруппировать результат по такому полю, обязательно предварительно ограничьте его длину через ВЫРАЗИТЬ(Поле КАК СТРОКА(Х)).УПОРЯДОЧИТЬ ПО): Нельзя сортировать результаты запроса по неограниченным строкам. Решение аналогично — предварительное приведение к строке фиксированной длины.РАЗЛИЧНЫЕ): Вы не сможете использовать ключевое слово РАЗЛИЧНЫЕ (SELECT DISTINCT) в запросе, если в списке выборки присутствует поле неограниченной длины.ОБЪЕДИНИТЬ): Оператор ОБЪЕДИНИТЬ выполняет неявную группировку строк для исключения дублей, что запрещено для длинных строк. Однако вы можете свободно использовать оператор ОБЪЕДИНИТЬ ВСЕ, так как он просто складывает результаты запросов без анализа уникальности строк.ПО): Нельзя связывать две таблицы по полям неограниченной длины (например, ПО Таблица1.Комментарий = Таблица2.Комментарий). Сначала приведите связующие поля к фиксированной длине.+ приведет к ошибке выполнения запроса.Рассмотрим важный нюанс при разработке отчетов в Системе компоновки данных (СКД). Часто разработчики, зная об ограничениях группировки, прямо в тексте запроса СКД пишут конструкцию ВЫРАЗИТЬ(ДлинныйТекст КАК СТРОКА(250)).
Это считается плохой практикой разработки. Если вы жестко обрежете строку в самом запросе, то конечный пользователь в печатной форме отчета увидит лишь обрезанный кусок длинного комментария или адреса, даже если группировка по этому полю в данный момент в настройках отчета не используется.
Как правильно поступать в СКД:
ВЫРАЗИТЬ.Строка, задав ограничение длины (например, Квалификаторы строки -> Длина: 1000).В этом случае СКД поступит интеллектуально: при выполнении группировок или отборов она сама на уровне СУБД применит ограничение длины, но в детальных записях отчета (в печатной форме) выведет текст полной, необрезанной длины.
Подведем итоги нашего разбора. Чтобы ваши запросы к полям неограниченной длины всегда работали быстро и без ошибок, придерживайтесь следующих правил:
NULL через знак равенства. Всегда используйте конструкцию ЕСТЬ NULL.NULL в неограниченном поле пишите Поле ЕСТЬ NULL напрямую, без использования функции ВЫРАЗИТЬ.ПОДСТРОКА(Поле, 1, 1) = "" или оператор ПОДОБНО "".ВЫРАЗИТЬ(Поле КАК СТРОКА(250)).