Как в запросе 1С отличить большие буквы от маленьких и учесть регистр символов?

Программист IT и автоматизация бизнеса
← На главную

Часто разработчики сталкиваются со следующей ситуацией: необходимо выбрать из базы данных элементы, наименование которых начинается со строчной (маленькой) буквы. Для этого пишется запрос, в котором используется условие вида ПОДСТРОКА(Номенклатура.Наименование, 1, 1) = "б". Однако в результате запрос возвращает номенклатуру, которая начинается как на маленькую "б", так и на заглавную "Б". Разберем подробно, почему так происходит и какие существуют методы решения данной задачи.

Почему язык запросов 1С игнорирует регистр символов?

Проанализируем архитектуру платформы. 1С:Предприятие не выполняет запросы самостоятельно, а транслирует их напрямую к СУБД (например, MS SQL Server или PostgreSQL). По внутренним архитектурным стандартам 1С базы данных всегда создаются со строгими настройками параметров сортировки (Collation), которые игнорируют регистр символов. Обычно это параметры вида Case Insensitive (например, _CI_AS).

Из-за этих настроек любые текстовые операции на уровне базы данных работают без учета регистра. Это касается операторов сравнения (=), использования оператора ПОДОБНО, а также механизмов группировки и сортировки. На уровне самого языка запросов 1С не существует встроенных функций или флагов, которые позволили бы принудительно включить точное регистрозависимое сравнение.

При этом важно понимать разницу: во встроенном языке 1С (при выполнении кода на сервере или клиенте) сравнение строк учитывает регистр, и выражение "б" <> "Б" вернет Истину. А вот в тексте запроса сравнение "б" = "Б" будет считаться истинным.

Чего категорически нельзя делать

Иногда возникает соблазн обойти это ограничение, зайдя напрямую в консоль управления СУБД (например, SQL Server Management Studio) и поменяв параметры сортировки конкретной колонки или таблицы на регистрозависимые (Case Sensitive, CS_AS). Делать это строго запрещено!

Такой подход грубо нарушает целостность работы платформы 1С. Это гарантированно приведет к критическим ошибкам на уровне базы данных (так называемый конфликт параметров сортировки или collation mismatch). В итоге это сделает невозможным дальнейшее нормальное функционирование базы, её обновление или реструктуризацию через Конфигуратор.

Решение 1: Фильтрация результата встроенным языком 1С

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

Посмотрим на пример реализации такого подхода:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Ссылка,
    |    Номенклатура.Наименование КАК Наименование
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    ПОДСТРОКА(Номенклатура.Наименование, 1, 1) = ""б""";

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    ПервыйСимвол = Лев(Выборка.Наименование, 1);
    
    // Программное сравнение строго учитывает регистр
    Если ПервыйСимвол = "б" Тогда
        // Обрабатываем нужный элемент со строчной буквы
        Сообщить(Выборка.Наименование);
    КонецЕсли;
КонецЦикла;

Этот метод отлично подходит для разовых обработок или небольших справочников. Однако, если записей в базе сотни тысяч, выгрузка их всех в память сервера (поскольку СУБД вернет и "Б", и "б") приведет к падению производительности и перерасходу оперативной памяти.

Решение 2: Архитектурный подход с использованием служебного реквизита

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

  1. Добавим в справочник новый служебный реквизит. Это может быть булево значение НачинаетсяСМаленькойБуквы или числовой реквизит КодПервогоСимвола. Обязательно проиндексируем этот реквизит для быстрого поиска.
  2. В модуле объекта справочника, в стандартном обработчике ПередЗаписью, напишем код, который будет анализировать наименование и автоматически заполнять наш служебный реквизит при сохранении элемента.
  3. В запросе мы будем обращаться уже к этому готовому реквизиту (например, ГДЕ НачинаетсяСМаленькойБуквы = ИСТИНА). Это позволит СУБД мгновенно задействовать индексы и вернуть только нужные записи.

Для надежного определения регистра символа во встроенном языке лучше всего использовать встроенную функцию КодСимвола(). Заглавные и строчные буквы имеют совершенно разные числовые коды в таблице символов. Сравнив полученное число с известным диапазоном кодов, мы со 100% точностью определим регистр.

Разберем пример кода для модуля объекта (обработчик ПередЗаписью):


Процедура ПередЗаписью(Отказ)
    Если ЗначениеЗаполнено(Наименование) Тогда
        // Получаем числовой код первого символа
        ЧисловойКод = КодСимвола(Лев(Наименование, 1));
        
        // Коды строчных русских букв от "а" до "я" находятся в диапазоне 1072 - 1103 (включая "ё" - 1105)
        Если (ЧисловойКод >= 1072 И ЧисловойКод <= 1103) Или ЧисловойКод = 1105 Тогда
            НачинаетсяСМаленькойБуквы = Истина;
        Иначе
            НачинаетсяСМаленькойБуквы = Ложь;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Теперь мы можем написать простой и быстрый запрос, который не требует последующей программной фильтрации и работает максимально оптимально:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Ссылка
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    Номенклатура.НачинаетсяСМаленькойБуквы = ИСТИНА";

Выбрав данный архитектурный подход, мы соблюдаем стандарты разработки 1С, обеспечиваем высокую производительность базы данных и навсегда решаем проблему поиска строк с учетом регистра символов в запросах.

← На главную