При разработке алгоритмов в среде 1С:Предприятие разработчики часто сталкиваются с необходимостью обработать данные таблицы значений через запрос к базе данных, чтобы избежать выполнения запросов внутри циклов. Выясним причину этой задачи и разберем практические способы передачи данных отдельной колонки таблицы значений в текст запроса.
Существует два основных подхода: выгрузка колонки в массив с последующей фильтрацией через условие В (&Параметр) и прямая передача таблицы значений в качестве параметра с помещением во временную таблицу. Разберем по шагам каждый вариант, их преимущества и ограничения.
Рассмотрим самый простой и быстрый способ, когда значения из определенной колонки таблицы значений выгружаются в стандартный массив и передаются в запрос через параметр.
Метод таблицы значений ВыгрузитьКолонку() создает массив и копирует в него все значения указанной колонки. Перед выгрузкой рекомендуется избавиться от дубликатов, свернув таблицу значений по нужной колонке.
Посмотрим на пример кода:
// Сворачиваем таблицу для исключения повторяющихся элементов
ТаблицаЗначений.Свернуть("Номенклатура");
// Выгружаем данные колонки в массив
МассивНоменклатуры = ТаблицаЗначений.ВыгрузитьКолонку("Номенклатура");
// Передаем массив в запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&МассивНоменклатуры)) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
РезультатЗапроса = Запрос.Выполнить();
Ограничения метода с массивом:
В (&Массив) на уровне СУБД разворачивается в оператор IN (...). При объеме массива более 1000–2000 элементов это может приводить к ошибкам ограничений СУБД по максимальному числу параметров и к существенному замедлению построения плана запроса.Проанализируем второй способ, который является стандартом разработки при больших или непредсказуемых объемах данных. Мы передаем таблицу значений целиком или только требуемую колонку в параметр запроса и помещаем ее во временную таблицу с помощью конструкции ПОМЕСТИТЬ.
Если в исходной таблице много лишних колонок, можно скопировать только нужную колонку методом Скопировать():
// Копируем только интересующую колонку
ОдноколоночнаяТЗ = ТаблицаЗначений.Скопировать(, "Номенклатура");
ОдноколоночнаяТЗ.Свернуть("Номенклатура");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ТЗ.Номенклатура КАК Номенклатура
|ПОМЕСТИТЬ ВтИсходныеДанные
|ИЗ
| &ТЗ КАК ТЗ
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВтИсходныеДанные.Номенклатура КАК Номенклатура,
| ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
|ИЗ
| ВтИсходныеДанные КАК ВтИсходныеДанные
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
| ПО ВтИсходныеДанные.Номенклатура = ТоварыНаСкладахОстатки.Номенклатура";
Запрос.УстановитьПараметр("ТЗ", ОдноколоночнаяТЗ);
РезультатЗапроса = Запрос.Выполнить();
Обратите внимание на важные детали при работе с временными таблицами:
ИНДЕКСИРОВАТЬ ПО ускоряет операции соединения таблиц на стороне СУБД.ВЫБРАТЬ РАЗЛИЧНЫЕ позволяет отсечь дубликаты на этапе помещения во временную таблицу.ОписаниеТипов при вызове метода Колонки.Добавить(), либо приводить их в тексте запроса с помощью функции ВЫРАЗИТЬ().Рассмотрим ситуацию, когда таблица находится на клиенте или отображается в элементах управляемой формы (тип ДанныеФормыКоллекция). Передать такую коллекцию напрямую в запрос нельзя.
В серверном контексте формы необходимо выполнить преобразование коллекции формы в полноценный объект ТаблицаЗначений с помощью платформенной функции ДанныеФормыВЗначение():
&НаСервере
Процедура ОбработатьДанныеФормыНаСервере()
// Преобразуем данные формы в таблицу значений
ТЗ = ДанныеФормыВЗначение(Объект.Товары, Тип("ТаблицаЗначений"));
// Выгружаем нужную колонку в массив или передаем таблицу в запрос
МассивНоменклатуры = ТЗ.ВыгрузитьКолонку("Номенклатура");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В (&МассивНоменклатуры)";
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
КонецЦикла;
КонецПроцедуры
Подведем итог и выделим критерии выбора подходящего способа:
ВыгрузитьКолонку(): Оптимален для небольших выборок (до нескольких сотен строк) и простых условий фильтрации ГДЕ Поле В (&Параметр).&ТЗ: Рекомендуется для средних и больших объемов данных, а также в сценариях, требующих выполнения ВНУТРЕННЕЕ СОЕДИНЕНИЕ или ЛЕВОЕ СОЕДИНЕНИЕ с индексацией полей.