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