При разработке и доработке печатных форм или отчетов часто возникает необходимость очистить наименование элемента справочника от служебных помет (например, текста в скобках, комментариев для пользователей или специальных кодов). Разберем, можно ли решить эту задачу непосредственно в запросе 1С, какие ограничения платформы при этом возникают и как правильно организовать обработку строк.
Язык запросов 1С имеет существенные технические ограничения при работе с текстовыми данными. В отличие от встроенного языка платформы или классического SQL, в запросе 1С отсутствуют:
СтрНайти()).СтрЗаменить()).Единственной базовой функцией для работы со строками в запросе является ПОДСТРОКА(). Однако она требует четко заданных параметров: исходная строка, начальная позиция и длина. Третий параметр (длина) обязан быть числовой константой или вычисляемым значением, но платформа не позволяет динамически определить точное местоположение искомого символа (например, открывающей скобки "(") без специальных ухищрений.
Рассмотрим чисто теоретический вариант решения, позволяющий найти первую открывающую скобку в наименовании прямо в тексте запроса. Для этого формируется вспомогательная таблица чисел, с помощью которой наименование раскладывается посимвольно.
Проанализируем следующий пример запроса:
ВЫБРАТЬ 0 КАК Поле
ПОМЕСТИТЬ Цифры
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 6
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 7
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 8
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9
;
ВЫБРАТЬ ПЕРВЫЕ 100
Числа1.Поле + 10 * Числа2.Поле КАК ПОЛЕ
ПОМЕСТИТЬ втСотня
ИЗ
Цифры КАК Числа1,
Цифры КАК Числа2
УПОРЯДОЧИТЬ ПО
ПОЛЕ
;
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
МИНИМУМ(втСотня.ПОЛЕ) КАК Номер
ПОМЕСТИТЬ НомераСкобок
ИЗ
Справочник.Номенклатура КАК Номенклатура,
втСотня КАК втСотня
ГДЕ
ПОДСТРОКА(Номенклатура.Наименование, втСотня.ПОЛЕ, 1) = "("
СГРУППИРОВАТЬ ПО
Номенклатура.Ссылка
;
ВЫБРАТЬ
ВЫБОР
КОГДА ЕСТЬNULL(НомераСкобок.Номер, 0) = 0
ТОГДА Номенклатура.Наименование
ИНАЧЕ ПОДСТРОКА(Номенклатура.Наименование, 1, НомераСкобок.Номер - 1)
КОНЕЦ КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ НомераСкобок КАК НомераСкобок
ПО Номенклатура.Ссылка = НомераСкобок.Ссылка
Разберем по шагам, как работает данная конструкция:
Цифры создает набор из 10 базовых цифр от 0 до 9.втСотня путем декартова произведения генерирует последовательность чисел от 0 до 99.НомераСкобок соединяет таблицу номенклатуры с таблицей чисел и выбирает по 1 символу через ПОДСТРОКА(), находя минимальную позицию, где встречается знак "(".Важное предупреждение: Использование подобного метода в реальных рабочих базах крайне не рекомендуется. Соединение справочника с таблицей чисел вызывает сплошное сканирование (Table Scan) и создаёт критическую нагрузку на СУБД. На больших объемах данных данный запрос приведет к катастрофическому падению производительности или аварийному завершению сеанса сервера 1С.
Выясним, какие подходы считаются правильными и наиболее эффективными в реальной разработке.
Если печатная форма или отчет формируются программно, проще и быстрее всего обработать полученную из запроса строку средствами встроенного языка 1С при заполнении параметров области вывода.
Посмотрим на пример кода:
ПозицияСкобки = СтрНайти(ИсходноеНаименование, "(");
Если ПозицияСкобки > 0 Тогда
ОчищенноеНаименование = СокрЛП(Лев(ИсходноеНаименование, ПозицияСкобки - 1));
Иначе
ОчищенноеНаименование = ИсходноеНаименование;
КонецЕсли;
Наиболее корректный архитектурный подход — хранить данные в том виде, в котором они должны выводиться. Для этого в справочник добавляется специальный реквизит (например, НаименованиеДляПечати или используется стандартное поле Полное наименование).
Заполнение реквизита можно автоматизировать с помощью подписки на событие ПередЗаписью или ПриЗаписи, где лишние символы отсекаются встроенным языком один раз при сохранении элемента. В отчетах и печатных формах выбирается уже готовое поле без дополнительной обработки.
Если отчет строится на СКД, не требуется усложнять сам текст запроса. Язык выражений компоновки данных поддерживает функции работы со строками.
В вкладке Вычисляемые поля СКД можно добавить новое поле и указать выражение:
ВЫБОР
КОГДА СтрНайти(Наименование, "(") > 0
ТОГДА СокрЛП(Лев(Наименование, СтрНайти(Наименование, "(") - 1))
ИНАЧЕ Наименование
КОНЕЦ
Также в выражениях СКД допускается вызов экспортируемых функций общих модулей конфигурации.
Если требуется выполнить обрезку исключительно в запросе и позиция символа находится в пределах первых нескольких знаков, можно применить каскадную проверку без использования таблиц чисел:
ВЫБОР
КОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 1) = "(" ТОГДА ""
КОГДА ПОДСТРОКА(Номенклатура.Наименование, 2, 1) = "(" ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 1)
КОГДА ПОДСТРОКА(Номенклатура.Наименование, 3, 1) = "(" ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 2)
КОГДА ПОДСТРОКА(Номенклатура.Наименование, 4, 1) = "(" ТОГДА ПОДСТРОКА(Номенклатура.Наименование, 1, 3)
ИНАЧЕ Номенклатура.Наименование
КОНЕЦ КАК НаименованиеДляПечати
Этот метод подходит только для коротких и строго ограниченных по формату строк, но он не создает нагрузки на систему и выполняется СУБД значительно быстрее искусственных соединений с таблицами чисел.