При написании запросов к информационной базе разработчики часто сталкиваются с ситуацией, когда необходимо отобрать документы или элементы справочников с заполненным текстовым реквизитом. Если тип этого реквизита определен как строка фиксированной длины, проблем не возникает. Однако при попытке сравнить строку неограниченной длины со значением пустой строки платформа выдает сообщение: «Неверные параметры в операции сравнения». Разберем по шагам, почему возникает эта ошибка и какими способами можно правильно поставить условие в запросе.
Проанализируем, как устроено хранение данных в реляционных СУБД. Поля с типом «Строка неограниченной длины» (а также любые строковые поля, длина которых в метаданных превышает 1024 символа) хранятся в специальных структурах для больших бинарных или текстовых объектов (LOB/CLOB, такие как nvarchar(max) в Microsoft SQL Server или text в PostgreSQL).
СУБД и сам язык запросов платформы 1С накладывают жесткие ограничения на использование таких полей. Их запрещено использовать напрямую в операциях:
=, <>, <, >, <=, >=) в секциях ГДЕ и ИМЕЮЩИЕ.+).ПО.СГРУППИРОВАТЬ ПО.УПОРЯДОЧИТЬ ПО (включая неявное АВТОУПОРЯДОЧИВАНИЕ).РАЗЛИЧНЫЕ или операции ОБЪЕДИНИТЬ (без слова ВСЕ).Поэтому прямая попытка написать условие НЕ Поле = &ПустаяСтрока или Поле <> "" неминуемо приводит к синтаксической ошибке на этапе выполнения запроса.
Самый распространенный и универсальный способ проверить, заполнена ли строка неограниченной длины, — явно привести ее к строке фиксированной длины. Для проверки факта заполненности нам достаточно ограничить поле всего одним символом.
Посмотрим на пример условия в запросе:
ВЫБРАТЬ
МойДокумент.Ссылка КАК Ссылка,
МойДокумент.ПриобретениеТоваровУслуг КАК Объект,
МойДокумент.ДокументИд КАК Значение
ИЗ
Документ.ДокументВходящий КАК МойДокумент
ГДЕ
ВЫРАЗИТЬ(МойДокумент.ДокументИд КАК Строка(1)) <> ""
Обратим внимание: использовать в секции ГДЕ функцию СокрЛП не требуется. Конструкция ВЫРАЗИТЬ(Поле КАК Строка(1)) преобразует тип к фиксированной длине, и платформа 1С корректно сравнивает первый символ с пустой строкой.
Важный нюанс: при явном приведении типа средствами некоторых СУБД строка может дополняться пробелами справа. Если реквизит содержит исключительно пробелы, условие сочтет его заполненным. Если требуется исключить строки, состоящие только из незначащих пробелов, надежнее применить проверку шаблоном.
В современных версиях платформы 1С:Предприятие в язык запросов добавлена встроенная функция ДлинаСтроки (или StringLength). С ее помощью можно вычислить точное количество символов в тексте, включая поля неограниченной длины.
Разберем пример с проверкой длины текста:
ВЫБРАТЬ
МойДокумент.Ссылка КАК Ссылка,
МойДокумент.ДокументИд КАК Значение
ИЗ
Документ.ДокументВходящий КАК МойДокумент
ГДЕ
ДлинаСтроки(МойДокумент.ДокументИд) > 0
Этот вариант делает текст запроса наглядным и прозрачным для понимания: мы сразу отсекаем записи, длина текста в которых равна нулю.
Оператор сравнения с шаблоном ПОДОБНО — один из немногих операторов в 1С, который разрешено применять к полям неограниченной длины напрямую, без предварительного усечения или приведения типа.
Рассмотрим два варианта использования этого оператора:
ГДЕ
МойДокумент.ДокументИд ПОДОБНО "_%"
_ означает ровно один любой обязательный символ, а знак процента % — любую последующую последовательность символов произвольной длины. Если в строке нет ни одного символа, условие вернет ложь.
ГДЕ
МойДокумент.ДокументИд ПОДОБНО "%[^ ]%"
[^ ] отбирает строки, в которых присутствует хотя бы один символ, отличный от пробела. Это позволяет отсечь документы, в реквизит которых случайно записали только пробелы или переводы строк.Еще один вариант, аналогичный приведению типа, — извлечение первого символа с помощью функции ПОДСТРОКА:
ГДЕ
ПОДСТРОКА(МойДокумент.ДокументИд, 1, 1) <> ""
Однако стандарты разработки 1С рекомендуют отдавать предпочтение конструкции ВЫРАЗИТЬ(... КАК СТРОКА(N)), поскольку в ряде СУБД (например, PostgreSQL) функции работы с подстроками могут транслироваться в менее оптимальные SQL-конструкции по сравнению со строгим приведением типов.
Проанализируем влияние подобных условий на быстродействие системы. Поля неограниченной длины не могут быть включены в индексы базы данных. Это означает, что любое условие в секции ГДЕ по такому полю (будь то ВЫРАЗИТЬ, ПОДОБНО или ДлинаСтроки) приведет к полному сканированию таблицы (Table Scan или Seq Scan).
Если таблица содержит десятки или сотни тысяч записей, выполнение такого запроса вызовет сильную нагрузку на дисковую подсистему и процессор сервера. Чтобы избежать проблем с производительностью, рассмотрим архитектурные альтернативы:
ДокументИд, GUID, внешний номер), ему не требуется неограниченная длина. Достаточно задать фиксированную длину (например, от 36 до 150 символов) и установить свойство Индексировать. Это позволит использовать стандартное быстрое сравнение через индекс.Булево (например, ИдентификаторЗаполнен). Заполнять его следует в событии ПередЗаписью объекта, а сам реквизит проиндексировать. Запрос с отбором по индексированному булеву полю выполнится мгновенно.