Работа с внешними источниками данных в запросах 1С — одна из самых частых задач для разработчика. Передача Таблицы Значений (ТЗ) или Табличной Части (ТЧ) в качестве параметра позволяет гибко фильтровать данные, не прибегая к динамическому формированию текста запроса. Однако на этом пути программисты часто сталкиваются как с банальными опечатками, так и со сложными логическими задачами, например, когда нужно найти объекты, удовлетворяющие сразу всем строкам из переданной таблицы.
В этой статье мы подробно разберем, как правильно передавать таблицу в запрос, как избежать ошибок при обращении к ее полям и как реализовать алгоритм отбора «все свойства из списка».
Рассмотрим ситуацию, когда при попытке выполнить запрос система выдает ошибку: {(2, 10)}: Поле не найдено "Таблица.Свойства". Проанализируем пример кода, который вызывает такое поведение:
Запрос.Параметры.Вставить("тзЗначенийСвойств", тзЗначенийСвойств);
Запрос.Текст = "ВЫБРАТЬ
| Таблица.Свойства КАК Свойства,
| Таблица.Значения КАК Значения
|ПОМЕСТИТЬ втСвойстваЗначения
|ИЗ
| &тзЗначенийСвойств КАК Таблица";
Выясним причину этой ошибки. В 1С запросы чувствительны к точному именованию колонок. Если в исходной таблице значений (или табличной части) колонка называется Свойство (в единственном числе), а в запросе вы обращаетесь к Таблица.Свойства (во множественном числе), запрос завершится аварийно. Всегда проверяйте соответствие имен колонок в метаданных обработки или программном коде создания ТЗ с текстом вашего запроса.
Если вы передаете в запрос не табличную часть (которая уже типизирована в конфигураторе), а созданную программно Таблицу Значений, критически важно явно задать типы её колонок. Без этого механизм временных таблиц не сможет корректно сопоставить данные с типами СУБД.
Разберем, как правильно подготовить ТЗ перед передачей в запрос:
ТЗ = Новый ТаблицаЗначений;
// Явно задаем описание типов для каждой колонки
МассивТиповСвойство = Новый Массив;
МассивТиповСвойство.Добавить(Тип("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
ОписаниеТиповСвойство = Новый ОписаниеТипов(МассивТиповСвойство);
ТЗ.Колонки.Добавить("Свойство", ОписаниеТиповСвойство);
ТЗ.Колонки.Добавить("Значение"); // Если тип составной, его также стоит описать максимально точно
Если колонки не будут типизированы, вы можете получить ошибку на этапе создания временной таблицы, так как 1С не сможет определить длину и тип полей для SQL-таблицы.
Часто возникает задача: найти элементы (например, номенклатуру), у которых есть все свойства, перечисленные в таблице параметров. Обычное внутреннее соединение ВНУТРЕННЕЕ СОЕДИНЕНИЕ работает по логике «ИЛИ» для строк: оно выберет номенклатуру, если у неё есть хотя бы одно совпадение по паре Свойство-Значение. Если в ТЗ три строки, в результат попадут товары, имеющие хотя бы одну из этих характеристик.
Чтобы реализовать строгий отбор (товар должен обладать всеми тремя характеристиками), мы применим метод группировки с фильтрацией по количеству. Разберем этот алгоритм по шагам:
ИМЕЮЩИЕ КОЛИЧЕСТВО(...) = &КоличествоСтрокВТЗ.Рассмотрим пример реализации такого запроса:
// Сначала определим количество уникальных условий в ТЗ
КоличествоУсловий = тзЗначенийСвойств.Количество();
Запрос.УстановитьПараметр("КоличествоУсловий", КоличествоУсловий);
Запрос.УстановитьПараметр("тзЗначенийСвойств", тзЗначенийСвойств);
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.Свойство КАК Свойство,
| ТЗ.Значение КАК Значение
|ПОМЕСТИТЬ втУсловия
|ИЗ
| &тзЗначенийСвойств КАК ТЗ
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДопРеквизиты.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ втУсловия КАК втУсловия
| ПО ДопРеквизиты.Свойство = втУсловия.Свойство
| И ДопРеквизиты.Значение = втУсловия.Значение
|СГРУППИРОВАТЬ ПО
| ДопРеквизиты.Ссылка
|ИМЕЮЩИЕ
| КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДопРеквизиты.Свойство) = &КоличествоУсловий";
В этом примере мы используем КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...), чтобы исключить влияние дублирующихся записей в базе данных, если таковые имеются. Если количество совпавших строк для конкретной номенклатуры равно общему числу строк в нашей таблице параметров, значит, эта номенклатура обладает всеми требуемыми свойствами.
Проанализируем ситуацию с большими объемами данных. Если в справочнике номенклатуры десятки тысяч записей, а в таблице значений — десятки строк, запрос может начать замедляться. Чтобы помочь планировщику СУБД, следует всегда индексировать временную таблицу по полям, участвующим в соединении.
Добавим индексацию в наш запрос:
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ.Свойство КАК Свойство,
| ТЗ.Значение КАК Значение
|ПОМЕСТИТЬ втУсловия
|ИЗ
| &тзЗначенийСвойств КАК ТЗ
|
|ИНДЕКСИРОВАТЬ ПО
| Свойство,
| Значение
|;
|...";
Важный момент: индексация временной таблицы имеет смысл только в том случае, если она будет использоваться в последующих соединениях этого же запроса. Если таблица просто выбирается, индекс только замедлит выполнение за счет времени на его создание.
Поскольку дополнительные реквизиты часто используют тип Характеристика.ДополнительныеРеквизитыИСведения, который является составным, 1С на уровне базы данных может создавать несколько полей для хранения типа и значения. При соединении по таким полям нагрузка на сервер возрастает.
Для повышения стабильности работы рекомендуется перед передачей ТЗ в запрос убедиться, что данные в ней «чистые»: используйте метод ТЗ.Свернуть("Свойство, Значение"). Это гарантирует, что КоличествоУсловий будет посчитано верно, и запрос не будет выполнять лишнюю работу по сопоставлению дублей.
Таким образом, использование ТЗ как параметра — это мощный инструмент, требующий внимательности к именам полей, типам данных и логике агрегации результатов. Следуя этим правилам, мы обеспечим быструю и корректную работу наших алгоритмов поиска и фильтрации.