При обработке внешних данных (например, при чтении логов телефонии, интеграции с внешними сервисами или загрузке файлов) часто возникает задача: передать в запрос 1С массив значений и получить результат в том же самом порядке, в котором элементы расположены в исходном массиве.
Однако если просто передать массив в условие В (&Массив), выводимый результат запроса окажется отсортирован не так, как в исходном файле или массиве.
Рассмотрим, почему стандартный запрос 1С не сохраняет последовательность элементов массива:
В (IN в SQL): Передача массива в условие ТелефонВФормате В (&Шаблон) лишь проверяет факт присутствия значения в списке. Система управления базами данных (СУБД) игнорирует позицию элементов внутри переданного массива.УПОРЯДОЧИТЬ ПО: Если в запросе не указана конструкция УПОРЯДОЧИТЬ ПО, СУБД возвращает записи в произвольном порядке, определяемом планом выполнения запроса, используемыми индексами и устройством физических таблиц.Проанализируем два основных способа решения этой задачи.
Если решение нужно реализовать целиком на стороне СУБД (например, когда в запросе выполняются дополнительные соединения, группировки или расчеты), передадим вместо массива объект ТаблицаЗначений с сохраненным индексом строки.
Разберем по шагам создание такой таблицы и связывание её в запросе:
ТаблицаЗначений с колонками Телефон (тип Строка) и НомерСтроки (тип Число).НомерСтроки текущий индекс (1, 2, 3 и т. д.).УПОРЯДОЧИТЬ ПО ВТ_Лог.НомерСтроки.Рассмотрим пример кода:
// 1. Создаем таблицу значений с явной типизацией
ТЗ_Лог = Новый ТаблицаЗначений;
ТЗ_Лог.Колонки.Добавить("Телефон", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(20)));
ТЗ_Лог.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 0)));
// 2. Заполняем ТЗ из массива с фиксацией порядка строк
Индекс = 1;
Для Каждого ТелефонИзЛога Из МассивНомеров Цикл
НоваяСтр = ТЗ_Лог.Добавить();
НоваяСтр.Телефон = ТелефонИзЛога;
НоваяСтр.НомерСтроки = Индекс;
Индекс = Индекс + 1;
КонецЦикла;
// 3. Формируем запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ_Лог.Телефон КАК Телефон,
| ТЗ_Лог.НомерСтроки КАК НомерСтроки
|ПОМЕСТИТЬ ВТ_Лог
|ИЗ
| &ТЗ_Лог КАК ТЗ_Лог
|ИНДЕКСИРОВАТЬ ПО
| Телефон
|;
|
|ВЫБРАТЬ
| ВТ_Лог.НомерСтроки КАК НомерСтроки,
| КонтактнаяИнформация.Пациент КАК Пациент
|ИЗ
| ВТ_Лог КАК ВТ_Лог
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформацияПациента.СрезПоследних(&ТекДата, ) КАК КонтактнаяИнформация
| ПО ВТ_Лог.Телефон = КонтактнаяИнформация.ТелефонВФормате
|УПОРЯДОЧИТЬ ПО
| ВТ_Лог.НомерСтроки";
Запрос.УстановитьПараметр("ТекДата", ТекущаяДата());
Запрос.УстановитьПараметр("ТЗ_Лог", ТЗ_Лог);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Пациент);
КонецЦикла;
Преимущество метода: Этот вариант полностью сохраняет повторяющиеся дубликаты из файла лога (если один номер звонил несколько раз на разных позициях) и возвращает результат строго в нужной последовательности.
Если задача заключается только в получении связанных данных по списку ключей без выполнения сложной бизнес-логики в базе, сортировку быстрее и проще перенести на сторону программного кода 1С.
Разберем по шагам выполнение постобработки:
ТелефонВФормате В (&Шаблон).Соответствие, где ключом будет выступать телефон, а значением — найденная ссылка (например, Пациент).Посмотрим на пример реализации:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КонтактнаяИнформацияСрезПоследних.ТелефонВФормате КАК Телефон,
| КонтактнаяИнформацияСрезПоследних.Пациент КАК Пациент
|ИЗ
| РегистрСведений.КонтактнаяИнформацияПациента.СрезПоследних(&ТекДата, ТелефонВФормате В (&Шаблон)) КАК КонтактнаяИнформацияСрезПоследних";
Запрос.УстановитьПараметр("ТекДата", ТекущаяДата());
Запрос.УстановитьПараметр("Шаблон", МассивНомеров);
Результат = Запрос.Выполнить();
// Заполняем соответствие для мгновенного поиска по ключу
СоответствиеПациентов = Новый Соответствие;
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
СоответствиеПациентов.Вставить(Выборка.Телефон, Выборка.Пациент);
КонецЦикла;
// Обходим исходный массив телефонов и выводим данные в порядке файла/массива
Для Каждого ТелефонИзЛога Из МассивНомеров Цикл
Пациент = СоответствиеПациентов[ТелефонИзЛога];
Если Пациент <> Неопределено Тогда
Сообщить(Пациент);
КонецЕсли;
КонецЦикла;
Важное замечание: При выборе второго способа поиск по ключу в объекте Соответствие выполняется со скоростью $O(1)$, что обеспечивает высокую производительность даже на десятках тысяч строк.