Как использовать таблицу значений в качестве параметра запроса и реализовать отбор по всем условиям (логика «И»)

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

Работа с внешними источниками данных в запросах 1С — одна из самых частых задач для разработчика. Передача Таблицы Значений (ТЗ) или Табличной Части (ТЧ) в качестве параметра позволяет гибко фильтровать данные, не прибегая к динамическому формированию текста запроса. Однако на этом пути программисты часто сталкиваются как с банальными опечатками, так и со сложными логическими задачами, например, когда нужно найти объекты, удовлетворяющие сразу всем строкам из переданной таблицы.

В этой статье мы подробно разберем, как правильно передавать таблицу в запрос, как избежать ошибок при обращении к ее полям и как реализовать алгоритм отбора «все свойства из списка».

Разбор типичной ошибки: поле не найдено

Рассмотрим ситуацию, когда при попытке выполнить запрос система выдает ошибку: {(2, 10)}: Поле не найдено "Таблица.Свойства". Проанализируем пример кода, который вызывает такое поведение:


Запрос.Параметры.Вставить("тзЗначенийСвойств", тзЗначенийСвойств);
Запрос.Текст = "ВЫБРАТЬ
               |    Таблица.Свойства КАК Свойства,
               |    Таблица.Значения КАК Значения
               |ПОМЕСТИТЬ втСвойстваЗначения
               |ИЗ
               |    &тзЗначенийСвойств КАК Таблица";

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

Обязательная типизация колонок при использовании ТЗ

Если вы передаете в запрос не табличную часть (которая уже типизирована в конфигураторе), а созданную программно Таблицу Значений, критически важно явно задать типы её колонок. Без этого механизм временных таблиц не сможет корректно сопоставить данные с типами СУБД.

Разберем, как правильно подготовить ТЗ перед передачей в запрос:


ТЗ = Новый ТаблицаЗначений;
// Явно задаем описание типов для каждой колонки
МассивТиповСвойство = Новый Массив;
МассивТиповСвойство.Добавить(Тип("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
ОписаниеТиповСвойство = Новый ОписаниеТипов(МассивТиповСвойство);

ТЗ.Колонки.Добавить("Свойство", ОписаниеТиповСвойство);
ТЗ.Колонки.Добавить("Значение"); // Если тип составной, его также стоит описать максимально точно

Если колонки не будут типизированы, вы можете получить ошибку на этапе создания временной таблицы, так как 1С не сможет определить длину и тип полей для SQL-таблицы.

Реализация логики «И» (отбор по всем условиям сразу)

Часто возникает задача: найти элементы (например, номенклатуру), у которых есть все свойства, перечисленные в таблице параметров. Обычное внутреннее соединение ВНУТРЕННЕЕ СОЕДИНЕНИЕ работает по логике «ИЛИ» для строк: оно выберет номенклатуру, если у неё есть хотя бы одно совпадение по паре Свойство-Значение. Если в ТЗ три строки, в результат попадут товары, имеющие хотя бы одну из этих характеристик.

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

  1. Поместим входящую таблицу параметров во временную таблицу.
  2. Соединим её со справочником (или регистром сведений), где хранятся значения.
  3. Сгруппируем результат по объекту (номенклатуре).
  4. Добавим условие ИМЕЮЩИЕ КОЛИЧЕСТВО(...) = &КоличествоСтрокВТЗ.

Рассмотрим пример реализации такого запроса:


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

Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТЗ.Свойство КАК Свойство,
    |    ТЗ.Значение КАК Значение
    |ПОМЕСТИТЬ втУсловия
    |ИЗ
    |    &тзЗначенийСвойств КАК ТЗ
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    ДопРеквизиты.Ссылка КАК Номенклатура
    |ИЗ
    |    Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
    |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ втУсловия КАК втУсловия
    |        ПО ДопРеквизиты.Свойство = втУсловия.Свойство
    |            И ДопРеквизиты.Значение = втУсловия.Значение
    |СГРУППИРОВАТЬ ПО
    |    ДопРеквизиты.Ссылка
    |ИМЕЮЩИЕ
    |    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДопРеквизиты.Свойство) = &КоличествоУсловий";

В этом примере мы используем КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ...), чтобы исключить влияние дублирующихся записей в базе данных, если таковые имеются. Если количество совпавших строк для конкретной номенклатуры равно общему числу строк в нашей таблице параметров, значит, эта номенклатура обладает всеми требуемыми свойствами.

Оптимизация производительности: индексация

Проанализируем ситуацию с большими объемами данных. Если в справочнике номенклатуры десятки тысяч записей, а в таблице значений — десятки строк, запрос может начать замедляться. Чтобы помочь планировщику СУБД, следует всегда индексировать временную таблицу по полям, участвующим в соединении.

Добавим индексацию в наш запрос:


Запрос.Текст = 
    "ВЫБРАТЬ
    |    ТЗ.Свойство КАК Свойство,
    |    ТЗ.Значение КАК Значение
    |ПОМЕСТИТЬ втУсловия
    |ИЗ
    |    &тзЗначенийСвойств КАК ТЗ
    |
    |ИНДЕКСИРОВАТЬ ПО
    |    Свойство,
    |    Значение
    |;
    |...";

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

Нюансы работы с составными типами

Поскольку дополнительные реквизиты часто используют тип Характеристика.ДополнительныеРеквизитыИСведения, который является составным, 1С на уровне базы данных может создавать несколько полей для хранения типа и значения. При соединении по таким полям нагрузка на сервер возрастает.

Для повышения стабильности работы рекомендуется перед передачей ТЗ в запрос убедиться, что данные в ней «чистые»: используйте метод ТЗ.Свернуть("Свойство, Значение"). Это гарантирует, что КоличествоУсловий будет посчитано верно, и запрос не будет выполнять лишнюю работу по сопоставлению дублей.

Таким образом, использование ТЗ как параметра — это мощный инструмент, требующий внимательности к именам полей, типам данных и логике агрегации результатов. Следуя этим правилам, мы обеспечим быструю и корректную работу наших алгоритмов поиска и фильтрации.

← На главную