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