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

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

При разработке в среде «1С:Предприятие» часто возникает задача хранения списков простых данных внутри документов без создания дополнительных табличных частей. Одним из таких способов является использование механизма дополнительных реквизитов (из Библиотеки стандартных подсистем — БСП), где создается реквизит с типом «Строка» и признаком «Многострочный режим». В этот реквизит пользователи могут записывать, например, список артикулов, кодов или серийных номеров — каждый с новой строки.

Однако при попытке выбрать документы по конкретному артикулу из этого списка с помощью обычного запроса разработчики сталкиваются с тем, что стандартное условие равенства = или условие вхождения В не работают. Давайте подробно разберем, почему так происходит, как решить эту задачу с помощью запроса и какие архитектурные нюансы необходимо учитывать.

Почему не работает простое сравнение?

Когда мы записываем несколько строк в одно текстовое поле, платформа 1С сохраняет их как единую строку, где строки разделены специальными невидимыми символами перевода строки (в платформе это переменная Символы.ПС, что соответствует символу LF с кодом 10 или комбинации CR + LF с кодами 13 и 10).

Если в реквизите записано:


ART-100
ART-200
ART-300

Для СУБД это единая строка вида "ART-100" + Символы.ПС + "ART-200" + Символы.ПС + "ART-300". Поэтому проверка на точное равенство ГДЕ Значение = "ART-200" вернет ложь, так как вся строка целиком не равна искомому артикулу.

---

Решение 1. Использование оператора ПОДОБНО с приведением типов

Для поиска подстроки внутри строки в языке запросов 1С применяется оператор ПОДОБНО. Однако при работе с дополнительными реквизитами БСП есть важный нюанс: реквизит Значение в табличной части ДополнительныеРеквизиты имеет составной тип данных (может хранить ссылки на различные справочники, числа, булево и строки). Оператор ПОДОБНО можно применять исключительно к строковым полям, иначе СУБД вернет ошибку.

Для обхода этого ограничения мы должны явно выразить тип значения как строку ограниченной длины с помощью конструкции ВЫРАЗИТЬ. Рассмотрим пример базового запроса:


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

При установке параметров запроса во встроенном языке необходимо окружить искомый артикул символами процента % (так называемыми масками или wildcards), которые обозначают любую последовательность произвольных символов:


Запрос.УстановитьПараметр("СвойствоАртикулы", СсылкаНаСвойствоАртикулы);
// Окружаем артикул процентами для поиска в любой части строки
Запрос.УстановитьПараметр("ШаблонПоиска", "%" + ИскомыйАртикул + "%");

---

Проблема ложных срабатываний при частичном совпадении

Описанный выше простой поиск по маске %Артикул% имеет один существенный недостаток — он может приводить к ложноположительным результатам из-за частичного совпадения строк.

Представим ситуацию: мы ищем артикул "ART-12". В документе записаны артикулы:


ART-123
ART-124

Шаблон "%ART-12%" успешно найдет этот документ, так как строка "ART-123" содержит внутри себя подстроку "ART-12". Но фактически нужного нам товара в документе нет! Чтобы избежать подобных ошибок, нам нужно искать точное совпадение строки с учетом символов перевода строки.

Решение 2. Точный поиск строки внутри многострочного текста

Искомый артикул в многострочном тексте может находиться в одном из четырех положений:

  1. Быть единственной строкой в реквизите (нет никаких переводов строк).
  2. Находиться в самом начале текста (после него идет символ перевода строки).
  3. Находиться в середине текста (окружен символами перевода строки с обеих сторон).
  4. Находиться в самом конце текста (перед ним идет символ перевода строки).

Поскольку платформа 1С не поддерживает конкатенацию строк с символом перевода строки непосредственно в тексте запроса, мы должны подготовить все возможные шаблоны во встроенном языке и передать их в качестве параметров запроса. Разберем этот алгоритм по шагам:


// Получаем символ перевода строки
ПС = Символы.ПС; 

Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ
	|	Поступление.Ссылка КАК Ссылка
	|ИЗ
	|	Документ.ПоступлениеОтПоставщика.ДополнительныеРеквизиты КАК Поступление
	|ГДЕ
	|	Поступление.Свойство = &СвойствоАртикулы
	|	И (ВЫРАЗИТЬ(Поступление.Значение КАК СТРОКА(1000)) = &ТочноеСовпадение
	|		ИЛИ ВЫРАЗИТЬ(Поступление.Значение КАК СТРОКА(1000)) ПОДОБНО &ВНачале
	|		ИЛИ ВЫРАЗИТЬ(Поступление.Значение КАК СТРОКА(1000)) ПОДОБНО &ВСередине
	|		ИЛИ ВЫРАЗИТЬ(Поступление.Значение КАК СТРОКА(1000)) ПОДОБНО &ВКонце)";

Запрос.УстановитьПараметр("СвойствоАртикулы", СсылкаНаСвойствоАртикулы);

// 1. Точное совпадение (если в реквизите всего одна строка)
Запрос.УстановитьПараметр("ТочноеСовпадение", ИскомыйАртикул);

// 2. Артикул в начале текста (после него идет перевод строки и любые символы)
Запрос.УстановитьПараметр("ВНачале", ИскомыйАртикул + ПС + "%");

// 3. Артикул в середине текста (окружен переводом строки с двух сторон)
Запрос.УстановитьПараметр("ВСередине", "%" + ПС + ИскомыйАртикул + ПС + "%");

// 4. Артикул в конце текста (перед ним идет перевод строки)
Запрос.УстановитьПараметр("ВКонце", "%" + ПС + ИскомыйАртикул);

РезультатЗапроса = Запрос.Выполнить();

Такой подход гарантирует стопроцентную точность поиска без риска зацепить похожие по написанию артикулы.

---

Проблема производительности оператора ПОДОБНО

Несмотря на то, что написанный выше запрос решает задачу, важно понимать его влияние на производительность системы. Использование оператора ПОДОБНО с ведущим знаком процента (например, %Значение%) заставляет СУБД выполнять полное сканирование таблицы (Table Scan или Index Scan) вместо быстрого поиска по индексу (Index Seek).

Когда документов в базе станет десятки тысяч, этот запрос начнет работать заметно медленнее, вызывая избыточную нагрузку на сервер управления базами данных и провоцируя транзакционные блокировки. Если эта процедура будет выполняться часто (например, при подборе товаров или проведении документов), это может стать критической точкой отказа системы.

---

Альтернативные варианты архитектуры решения

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

Вариант А. Создание собственной табличной части в расширении

Самое чистое архитектурное решение — добавить к документу собственную табличную часть (например, АртикулыДокумента) через механизм расширений конфигурации. Каждая строка табличной части будет содержать ровно один артикул в индексированном строковом реквизите. В этом случае поиск будет происходить мгновенно через обычное соединение таблиц:


ВЫБРАТЬ РАЗЛИЧНЫЕ
	ДокументСсылка.Ссылка КАК Ссылка
ИЗ
	Документ.ПоступлениеОтПоставщика КАК ДокументСсылка
	ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПоступлениеОтПоставщика.АртикулыДокумента КАК Артикулы
		ПО Артикулы.Ссылка = ДокументСсылка.Ссылка
ГДЕ
	Артикулы.Артикул = &ИскомыйАртикул

Вариант Б. Использование подчиненного регистра сведений

Если по каким-то причинам не хочется раздувать структуру самого документа, можно создать независимый или подчиненный регистр сведений (например, АртикулыДокументов) с измерениями Документ (тип: документ-ссылка) и Артикул (тип: строка, длина до 50 символов, с включенным индексированием). При проведении или записи документа данные из многострочной строки будут автоматически записываться в этот регистр. Поиск по индексированному измерению регистра сведений в СУБД происходит за миллисекунды.

Вариант В. Множественные значения дополнительных реквизитов БСП

Если вы работаете в типовой конфигурации и используете БСП, проверьте настройки дополнительных реквизитов. Современные версии БСП поддерживают работу со свойствами, имеющими тип значения «Дополнительное значение» с возможностью выбора множества значений. В этом случае для одного документа система сама создаст несколько строк в табличной части ДополнительныеРеквизиты, и поиск сведется к простому равенству по значению ссылки справочника, что также является крайне быстрой операцией.

← На главную