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

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

При написании запросов к информационной базе 1С разработчики нередко сталкиваются с ситуацией, когда строковый реквизит документа или справочника имеет фиксированную длину (например, 8 символов), и требуется отобрать записи, где это поле не заполнено. Возникает вопрос: нужно ли в условии указывать строку из восьми пробелов, достаточно ли сравнения с пустой строкой "", и как на это влияют особенности конкретной СУБД. Разберем эту задачу подробно со всеми техническими нюансами и вариантами реализации.

Проанализируем сначала природу строковых реквизитов. В метаданных 1С для строки можно задать фиксированную длину, если не установлен флаг Переменная длина. В таблицах реляционных баз данных (таких как MS SQL Server или PostgreSQL) такие поля создаются с типом CHAR. Если значение не заполнено пользователем, платформа при сохранении объекта автоматически дополняет строку пробелами до заданной длины.

Вариант 1. Классическое сравнение на пустую строку и строку пробелов

Посмотрим на самое простое условие, которое упоминается в большинстве типовых ситуаций. В запросе можно проверить поле как на полное отсутствие символов, так и на заполненность пробелами нужной длины.

Рассмотрим пример кода условия в секции ГДЕ:


ГДЕ
    Документ.Реквизит = ""
    ИЛИ Документ.Реквизит = "        "

Выясним причину, почему в одних случаях работает простое сравнение с "", а в других требуется дополнительная проверка:

  1. Поведение MS SQL Server: по стандарту SQL при сравнении строк оператором = завершающие пробелы игнорируются (короткая строка виртуально дополняется пробелами до длины длинной). Поэтому на MS SQL Server условие Реквизит = "" вернет ИСТИНА даже для поля из 8 пробелов.
  2. Поведение PostgreSQL: для строк типа VARCHAR или в некоторых версиях/конфигурациях СУБД строка, состоящая только из физических пробелов, при точном сравнении с "" может вернуть ЛОЖЬ. В таких ситуациях явное указание строки из пробелов страхует результат выборки.

Вариант 2. Использование встроенных строковых функций (1С:Предприятие 8.3.20 и выше)

Начиная с версии платформы 8.3.20, разработчикам стал доступен расширенный набор строковых функций непосредственно в языке запросов. Это наиболее универсальный и современный способ, избавляющий от необходимости вручную высчитывать количество пробелов под длину конкретного реквизита.

Разберем по шагам применение функции СОКРЛП (сокращение незначащих пробелов слева и справа). Если реквизит состоит только из пробелов, функция вернет пустую строку нулевой длины.

Посмотрим на пример условия:


ГДЕ
    СОКРЛП(Документ.Реквизит) = ""

Также можно воспользоваться вычислением длины очищенной строки:


ГДЕ
    ДЛИНАСТРОКИ(СОКРЛП(Документ.Реквизит)) = 0

Такой подход делает код устойчивым: если в метаданных конфигурации изменится длина реквизита (например, увеличится с 8 до 10 символов), условие запроса продолжит работать корректно без каких-либо правок.

Вариант 3. Использование оператора ПОДОБНО (для платформы ниже 8.3.20)

Если конфигурация работает на версии платформы ниже 8.3.20, где строковые функции в запросах еще не поддерживаются, рассмотрим универсальный способ через поиск символов с помощью оператора ПОДОБНО.

Идея заключается в том, чтобы проверить, содержит ли поле хотя бы один символ, отличный от пробела. Шаблон [^ ] обозначает отрицание пробела. Соответственно, если отрицать наличие такого символа во всей строке, мы получим только пустые или состоящие исключительно из пробелов поля:


ГДЕ
    НЕ Документ.Реквизит ПОДОБНО "%[^ ]%"

Этот способ одинаково надежно отрабатывает на любых версиях платформы и во всех СУБД, независимо от заданной длины реквизита в метаданных.

Учет значений NULL в сложных запросах

Проанализируем важную особенность: если выборка строится с использованием левого соединения (ЛЕВОЕ СОЕДИНЕНИЕ) или реквизит имеет составной тип данных, неинициализированное значение в выборке может быть равно значению NULL.

В реляционной логике любое прямое сравнение со значением NULL (будь то = "" или проверка через ПОДОБНО) возвращает ЛОЖЬ. Чтобы запрос не потерял нужные документы, обязательно добавим проверку или замещение через функцию ЕСТЬNULL:


ГДЕ
    ЕСТЬNULL(Документ.Реквизит, "") = ""
    ИЛИ ЕСТЬNULL(Документ.Реквизит, "") = "        "

Или в сочетании с СОКРЛП для современных платформ:


ГДЕ
    СОКРЛП(ЕСТЬNULL(Документ.Реквизит, "")) = ""

Архитектурная рекомендация: нормализация данных перед записью

Рассмотрим вопрос производительности. Применение функций (СОКРЛП) или условий с маской ПОДОБНО "%..." к колонкам таблиц делает условие неиндексируемым (non-sargable). СУБД не сможет использовать индекс по этому реквизиту и будет вынуждена сканировать всю таблицу целиком (Table Scan).

Чтобы избежать проблем с производительностью в высоконагруженных базах данных, правильнее всего пресекать появление "хвостовых" и пустых пробельных строк еще на этапе записи объекта. Для этого в модуле объекта в обработчике ПередЗаписью выполняем очистку значения:


Процедура ПередЗаписью(Отказ)
    ЭтотОбъект.Реквизит = СокрЛП(ЭтотОбъект.Реквизит);
КонецПроцедуры

Если строка всегда будет нормализована при записи, в запросах будет достаточно лаконичной и быстрой проверки ГДЕ Документ.Реквизит = "", которая сможет эффективно задействовать индекс.

← На главную