При написании запросов к информационной базе 1С разработчики нередко сталкиваются с ситуацией, когда строковый реквизит документа или справочника имеет фиксированную длину (например, 8 символов), и требуется отобрать записи, где это поле не заполнено. Возникает вопрос: нужно ли в условии указывать строку из восьми пробелов, достаточно ли сравнения с пустой строкой "", и как на это влияют особенности конкретной СУБД. Разберем эту задачу подробно со всеми техническими нюансами и вариантами реализации.
Проанализируем сначала природу строковых реквизитов. В метаданных 1С для строки можно задать фиксированную длину, если не установлен флаг Переменная длина. В таблицах реляционных баз данных (таких как MS SQL Server или PostgreSQL) такие поля создаются с типом CHAR. Если значение не заполнено пользователем, платформа при сохранении объекта автоматически дополняет строку пробелами до заданной длины.
Посмотрим на самое простое условие, которое упоминается в большинстве типовых ситуаций. В запросе можно проверить поле как на полное отсутствие символов, так и на заполненность пробелами нужной длины.
Рассмотрим пример кода условия в секции ГДЕ:
ГДЕ
Документ.Реквизит = ""
ИЛИ Документ.Реквизит = " "
Выясним причину, почему в одних случаях работает простое сравнение с "", а в других требуется дополнительная проверка:
= завершающие пробелы игнорируются (короткая строка виртуально дополняется пробелами до длины длинной). Поэтому на MS SQL Server условие Реквизит = "" вернет ИСТИНА даже для поля из 8 пробелов.VARCHAR или в некоторых версиях/конфигурациях СУБД строка, состоящая только из физических пробелов, при точном сравнении с "" может вернуть ЛОЖЬ. В таких ситуациях явное указание строки из пробелов страхует результат выборки.Начиная с версии платформы 8.3.20, разработчикам стал доступен расширенный набор строковых функций непосредственно в языке запросов. Это наиболее универсальный и современный способ, избавляющий от необходимости вручную высчитывать количество пробелов под длину конкретного реквизита.
Разберем по шагам применение функции СОКРЛП (сокращение незначащих пробелов слева и справа). Если реквизит состоит только из пробелов, функция вернет пустую строку нулевой длины.
Посмотрим на пример условия:
ГДЕ
СОКРЛП(Документ.Реквизит) = ""
Также можно воспользоваться вычислением длины очищенной строки:
ГДЕ
ДЛИНАСТРОКИ(СОКРЛП(Документ.Реквизит)) = 0
Такой подход делает код устойчивым: если в метаданных конфигурации изменится длина реквизита (например, увеличится с 8 до 10 символов), условие запроса продолжит работать корректно без каких-либо правок.
Если конфигурация работает на версии платформы ниже 8.3.20, где строковые функции в запросах еще не поддерживаются, рассмотрим универсальный способ через поиск символов с помощью оператора ПОДОБНО.
Идея заключается в том, чтобы проверить, содержит ли поле хотя бы один символ, отличный от пробела. Шаблон [^ ] обозначает отрицание пробела. Соответственно, если отрицать наличие такого символа во всей строке, мы получим только пустые или состоящие исключительно из пробелов поля:
ГДЕ
НЕ Документ.Реквизит ПОДОБНО "%[^ ]%"
Этот способ одинаково надежно отрабатывает на любых версиях платформы и во всех СУБД, независимо от заданной длины реквизита в метаданных.
Проанализируем важную особенность: если выборка строится с использованием левого соединения (ЛЕВОЕ СОЕДИНЕНИЕ) или реквизит имеет составной тип данных, неинициализированное значение в выборке может быть равно значению NULL.
В реляционной логике любое прямое сравнение со значением NULL (будь то = "" или проверка через ПОДОБНО) возвращает ЛОЖЬ. Чтобы запрос не потерял нужные документы, обязательно добавим проверку или замещение через функцию ЕСТЬNULL:
ГДЕ
ЕСТЬNULL(Документ.Реквизит, "") = ""
ИЛИ ЕСТЬNULL(Документ.Реквизит, "") = " "
Или в сочетании с СОКРЛП для современных платформ:
ГДЕ
СОКРЛП(ЕСТЬNULL(Документ.Реквизит, "")) = ""
Рассмотрим вопрос производительности. Применение функций (СОКРЛП) или условий с маской ПОДОБНО "%..." к колонкам таблиц делает условие неиндексируемым (non-sargable). СУБД не сможет использовать индекс по этому реквизиту и будет вынуждена сканировать всю таблицу целиком (Table Scan).
Чтобы избежать проблем с производительностью в высоконагруженных базах данных, правильнее всего пресекать появление "хвостовых" и пустых пробельных строк еще на этапе записи объекта. Для этого в модуле объекта в обработчике ПередЗаписью выполняем очистку значения:
Процедура ПередЗаписью(Отказ)
ЭтотОбъект.Реквизит = СокрЛП(ЭтотОбъект.Реквизит);
КонецПроцедуры
Если строка всегда будет нормализована при записи, в запросах будет достаточно лаконичной и быстрой проверки ГДЕ Документ.Реквизит = "", которая сможет эффективно задействовать индекс.